Imported existing code

This commit is contained in:
Hazim Gazov
2010-04-02 02:48:44 -03:00
parent 48fbc5ae91
commit 7a86d01598
13996 changed files with 2468699 additions and 0 deletions

View File

@@ -0,0 +1,302 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_COROUTINE_HPP_20060512
#define BOOST_COROUTINE_COROUTINE_HPP_20060512
// On Linux systems, use native swapcontext() et al. rather than
// Boost.Coroutine homebrew assembler
#define BOOST_COROUTINE_NO_ASM
// default_context_impl.hpp must be first for weird Apple bug
#include <boost/coroutine/detail/default_context_impl.hpp>
#include <cstddef>
#include <boost/preprocessor/repetition.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/type_traits.hpp>
#include <boost/call_traits.hpp>
#include <boost/coroutine/detail/arg_max.hpp>
#include <boost/coroutine/detail/coroutine_impl.hpp>
#include <boost/coroutine/detail/is_callable.hpp>
#include <boost/coroutine/detail/argument_packer.hpp>
#include <boost/coroutine/detail/argument_unpacker.hpp>
#include <boost/coroutine/detail/signature.hpp>
#include <boost/coroutine/detail/index.hpp>
#include <boost/coroutine/detail/coroutine_traits.hpp>
#include <boost/coroutine/detail/coroutine_accessor.hpp>
#include <boost/coroutine/move.hpp>
#include <boost/coroutine/detail/fix_result.hpp>
#include <boost/coroutine/detail/self.hpp>
namespace boost { namespace coroutines {
namespace detail {
template<typename T>
struct optional_result_type :
boost::mpl::if_<boost::is_same<T, void>,
void,
boost::optional<T> > { };
template<typename T>
BOOST_DEDUCED_TYPENAME
boost::enable_if<boost::is_same<T, void> >::type
optional_result() {}
template<typename T>
BOOST_DEDUCED_TYPENAME
boost::disable_if<boost::is_same<T, void>,
BOOST_DEDUCED_TYPENAME
optional_result_type<T>::type
>::type
optional_result() {
return BOOST_DEDUCED_TYPENAME
optional_result_type<T>::type();
}
}
template<typename Signature, typename Context>
class coroutine;
template<typename T>
struct is_coroutine : boost::mpl::false_{};
template<typename Sig, typename Con>
struct is_coroutine<coroutine<Sig, Con> > : boost::mpl::true_{};
template<typename Signature,
typename ContextImpl = detail::default_context_impl>
class coroutine : public movable<coroutine<Signature, ContextImpl> > {
public:
typedef coroutine<Signature, ContextImpl> type;
typedef ContextImpl context_impl;
typedef Signature signature_type;
friend struct detail::coroutine_accessor;
typedef BOOST_DEDUCED_TYPENAME
detail::coroutine_traits<signature_type>
::result_type result_type;
typedef BOOST_DEDUCED_TYPENAME
detail::coroutine_traits<signature_type>
::result_slot_type result_slot_type;
typedef BOOST_DEDUCED_TYPENAME
detail::coroutine_traits<signature_type>
::yield_result_type yield_result_type;
typedef BOOST_DEDUCED_TYPENAME
detail::coroutine_traits<signature_type>
::result_slot_traits result_slot_traits;
typedef BOOST_DEDUCED_TYPENAME
detail::coroutine_traits<signature_type>
::arg_slot_type arg_slot_type;
typedef BOOST_DEDUCED_TYPENAME
detail::coroutine_traits<signature_type>
::arg_slot_traits arg_slot_traits;
typedef detail::coroutine_impl<type, context_impl> impl_type;
typedef BOOST_DEDUCED_TYPENAME impl_type::pointer impl_ptr;
typedef detail::coroutine_self<type> self;
coroutine() : m_pimpl(0) {}
template<typename Functor>
coroutine (Functor f,
std::ptrdiff_t stack_size = detail::default_stack_size,
BOOST_DEDUCED_TYPENAME boost::enable_if<
boost::mpl::and_<
detail::is_callable<Functor>,
boost::mpl::not_<is_coroutine<Functor> >
> >
::type * = 0
) :
m_pimpl(impl_type::create(f, stack_size)) {}
coroutine(move_from<coroutine> src)
: m_pimpl(src->m_pimpl) {
src->m_pimpl = 0;
}
coroutine& operator=(move_from<coroutine> src) {
coroutine(src).swap(*this);
return *this;
}
coroutine& swap(coroutine& rhs) {
std::swap(m_pimpl, rhs.m_pimpl);
return *this;
}
friend
void swap(coroutine& lhs, coroutine& rhs) {
lhs.swap(rhs);
}
# define BOOST_COROUTINE_generate_argument_n_type(z, n, traits_type) \
typedef BOOST_DEDUCED_TYPENAME traits_type ::template at<n>::type \
BOOST_PP_CAT(BOOST_PP_CAT(arg, n), _type); \
/**/
BOOST_PP_REPEAT(BOOST_COROUTINE_ARG_MAX,
BOOST_COROUTINE_generate_argument_n_type,
arg_slot_traits);
static const int arity = arg_slot_traits::length;
struct yield_traits {
BOOST_PP_REPEAT(BOOST_COROUTINE_ARG_MAX,
BOOST_COROUTINE_generate_argument_n_type,
result_slot_traits);
static const int arity = result_slot_traits::length;
};
# undef BOOST_COROUTINE_generate_argument_n_type
# define BOOST_COROUTINE_param_with_default(z, n, type_prefix) \
BOOST_DEDUCED_TYPENAME call_traits \
<BOOST_PP_CAT(BOOST_PP_CAT(type_prefix, n), _type)>::param_type \
BOOST_PP_CAT(arg, n) = \
BOOST_PP_CAT(BOOST_PP_CAT(type_prefix, n), _type)() \
/**/
result_type operator()
(BOOST_PP_ENUM
(BOOST_COROUTINE_ARG_MAX,
BOOST_COROUTINE_param_with_default,
arg)) {
return call_impl
(arg_slot_type(BOOST_PP_ENUM_PARAMS
(BOOST_COROUTINE_ARG_MAX,
arg)));
}
BOOST_DEDUCED_TYPENAME
detail::optional_result_type<result_type>::type
operator()
(const std::nothrow_t&
BOOST_PP_ENUM_TRAILING
(BOOST_COROUTINE_ARG_MAX,
BOOST_COROUTINE_param_with_default,
arg)) {
return call_impl_nothrow
(arg_slot_type(BOOST_PP_ENUM_PARAMS
(BOOST_COROUTINE_ARG_MAX,
arg)));
}
# undef BOOST_COROUTINE_param_typedef
# undef BOOST_COROUTINE_param_with_default
typedef void(coroutine::*bool_type)();
operator bool_type() const {
return good()? &coroutine::bool_type_f: 0;
}
bool operator==(const coroutine& rhs) {
return m_pimpl == rhs.m_pimpl;
}
void exit() {
BOOST_ASSERT(m_pimpl);
m_pimpl->exit();
}
bool waiting() const {
BOOST_ASSERT(m_pimpl);
return m_pimpl->waiting();
}
bool pending() const {
BOOST_ASSERT(m_pimpl);
return m_pimpl->pending();
}
bool exited() const {
BOOST_ASSERT(m_pimpl);
return m_pimpl->exited();
}
bool empty() const {
return m_pimpl == 0;
}
protected:
// The second parameter is used to avoid calling this constructor
// by mistake from other member funcitons (specifically operator=).
coroutine(impl_type * pimpl, detail::init_from_impl_tag) :
m_pimpl(pimpl) {}
void bool_type_f() {}
bool good() const {
return !empty() && !exited() && !waiting();
}
result_type call_impl(arg_slot_type args) {
BOOST_ASSERT(m_pimpl);
m_pimpl->bind_args(&args);
BOOST_DEDUCED_TYPENAME impl_type::local_result_slot_ptr ptr(m_pimpl);
m_pimpl->invoke();
return detail::fix_result<result_slot_traits>(*m_pimpl->result());
}
BOOST_DEDUCED_TYPENAME
detail::optional_result_type<result_type>::type
call_impl_nothrow(arg_slot_type args) {
BOOST_ASSERT(m_pimpl);
m_pimpl->bind_args(&args);
BOOST_DEDUCED_TYPENAME impl_type::local_result_slot_ptr ptr(m_pimpl);
if(!m_pimpl->wake_up())
return detail::optional_result<result_type>();
return detail::fix_result<result_slot_traits>(*m_pimpl->result());
}
impl_ptr m_pimpl;
void acquire() {
m_pimpl->acquire();
}
void release() {
m_pimpl->release();
}
std::size_t
count() const {
return m_pimpl->count();
}
impl_ptr get_impl() {
return m_pimpl;
}
};
} }
#endif

View File

@@ -0,0 +1,34 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_ARG_MAX_HPP_20060728
# define BOOST_COROUTINE_DETAIL_ARG_MAX_HPP_20060728
# ifndef BOOST_COROUTINE_ARG_MAX
# define BOOST_COROUTINE_ARG_MAX 10
# endif
#endif

View File

@@ -0,0 +1,70 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_ARGUMENT_PACKER_HPP_20060601
#define BOOST_COROUTINE_ARGUMENT_PACKER_HPP_20060601
#include <boost/preprocessor/control/if.hpp>
#include <boost/preprocessor/punctuation/comma_if.hpp>
#include <boost/preprocessor/repetition.hpp>
#include <boost/preprocessor/tuple/eat.hpp>
namespace boost { namespace coroutines { namespace detail {
#define BOOST_COROUTINE_DETAIL_TEMPLATE_PARAMETERS(n) \
template<BOOST_PP_ENUM_PARAMS(n, typename T)> \
/**/
#define BOOST_COROUTINE_ARGUMENT_PACKER(z, n, parm_tuple) \
BOOST_PP_IF(n, \
BOOST_COROUTINE_DETAIL_TEMPLATE_PARAMETERS , \
BOOST_PP_TUPLE_EAT(1) )(n) \
BOOST_PP_TUPLE_ELEM(3, 0, parm_tuple) \
(BOOST_PP_ENUM_BINARY_PARAMS(n, T, arg)) { \
typedef BOOST_PP_TUPLE_ELEM(3, 2, parm_tuple) parm_type; \
return BOOST_PP_TUPLE_ELEM(3, 1, parm_tuple) \
(parm_type \
(BOOST_PP_ENUM_PARAMS(n, arg))); \
} \
/**/
#define BOOST_COROUTINE_ARGUMENT_PACKER_EX(z, n, parm_tuple) \
template<typename Arg \
BOOST_PP_COMMA_IF(n) \
BOOST_PP_ENUM_PARAMS(n, typename T)> \
BOOST_PP_TUPLE_ELEM(3, 0, parm_tuple) \
(Arg arg \
BOOST_PP_COMMA_IF(n) \
BOOST_PP_ENUM_BINARY_PARAMS(n, T, arg)) { \
typedef BOOST_PP_TUPLE_ELEM(3, 2, parm_tuple) parm_type; \
return BOOST_PP_TUPLE_ELEM(3, 1, parm_tuple)( arg, parm_type \
(BOOST_PP_ENUM_PARAMS(n, arg))); \
} \
/**/
} } }
#endif

View File

@@ -0,0 +1,134 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_ARGUMENT_UNPACKER_HPP_20060601
#define BOOST_COROUTINE_ARGUMENT_UNPACKER_HPP_20060601
#include <boost/preprocessor/control/if.hpp>
#include <boost/preprocessor/repetition.hpp>
#include <boost/utility/result_of.hpp>
#include <boost/coroutine/detail/index.hpp>
#include <boost/coroutine/detail/arg_max.hpp>
namespace boost { namespace coroutines { namespace detail {
template<typename Traits, int Len>
struct unpacker_n;
template<typename Traits, int Len>
struct unpacker_ex_n;
#define BOOST_COROUTINE_ARGUMENT_UNPACKER(z, len, unused) \
template<typename Traits> \
struct unpacker_n<Traits, len> { \
template<typename Functor, typename Tuple> \
struct result {/*for result_of compatibility*/ \
typedef typename boost::result_of \
<Functor(BOOST_PP_ENUM_BINARY_PARAMS \
(len, typename Traits::template at<index_ , > \
::type BOOST_PP_INTERCEPT))>::type type; \
}; \
template<typename Functor, typename Tuple> \
typename result<Functor, Tuple>::type operator() \
(Functor& f, Tuple& parms){ \
using boost::get; /*tuples::get cannot be found via ADL*/ \
return f(BOOST_PP_ENUM_BINARY_PARAMS \
(len, \
get<index_, > \
(parms) BOOST_PP_INTERCEPT)); \
} \
}; \
/**/
#define BOOST_COROUTINE_ARGUMENT_UNPACKER_EX(z, len, unused) \
template<typename Traits> \
struct unpacker_ex_n<Traits, len > { \
template<typename Functor, \
typename First, \
typename Tuple> \
struct result { \
typedef typename boost::result_of \
<Functor(First BOOST_PP_COMMA_IF(len) \
BOOST_PP_ENUM_BINARY_PARAMS \
(len, typename Traits \
::template at<index_ , >::type BOOST_PP_INTERCEPT))> \
::type type; \
}; \
\
template<typename Functor, \
typename First, \
typename Tuple> \
typename result<Functor, First, Tuple>::type \
operator()(Functor& f, First& arg0, Tuple& parms){ \
using boost::get; /*tuples::get cannot be found via ADL*/ \
return f(arg0 \
BOOST_PP_COMMA_IF(len) \
BOOST_PP_ENUM_BINARY_PARAMS \
(len, \
get<index_, > \
(parms) BOOST_PP_INTERCEPT) ); \
} \
}; \
/**/
BOOST_PP_REPEAT(BOOST_COROUTINE_ARG_MAX,
BOOST_COROUTINE_ARGUMENT_UNPACKER, ~);
BOOST_PP_REPEAT(BOOST_COROUTINE_ARG_MAX,
BOOST_COROUTINE_ARGUMENT_UNPACKER_EX, ~);
// Somehow VCPP 8.0 chockes if the Trait for unpack[_ex]
// is explicitly specified. We use an empty dispatch
// tag to let the compiler deduce it.
template<typename Trait>
struct trait_tag {};
/**
* Inovoke function object @p f passing all
* elements in tuple @p parms as distinct parameters.
*/
template<typename Traits, typename Functor, typename Tuple>
inline
typename unpacker_n<Traits, Traits::length>
::template result<Functor, Tuple>::type
unpack(Functor f, Tuple& parms, trait_tag<Traits>) {
return unpacker_n<Traits, Traits::length>()(f, parms);
}
/**
* Inovke function object @p f passing argument @p arg0 and all
* elements in tuple @p parms as distinct parameters.
*/
template<typename Traits, typename Functor, typename First, typename Tuple>
inline
typename unpacker_ex_n<Traits, Traits::length>::
template result<Functor, First, Tuple>::type
unpack_ex(Functor f, First& arg0, Tuple& parms, trait_tag<Traits>) {
return unpacker_ex_n<Traits, Traits::length>()
(f, arg0, parms);
}
} } }
#endif

View File

@@ -0,0 +1,123 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_CALL_IMPL_HPP_20060728
#define BOOST_COROUTINE_DETAIL_CALL_IMPL_HPP_20060728
#include <boost/preprocessor/repetition.hpp>
#include <boost/call_traits.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/bind.hpp>
#include <boost/coroutine/coroutine.hpp>
#include <boost/coroutine/detail/arg_max.hpp>
#include <boost/coroutine/detail/signal.hpp>
#include <boost/coroutine/detail/coroutine_accessor.hpp>
namespace boost { namespace coroutines { namespace detail {
#define BOOST_COROUTINE_tuple_param_n(z, n, tuple)\
BOOST_DEDUCED_TYPENAME \
boost::tuples::element<n, tuple>::type \
BOOST_PP_CAT(arg, n) \
/**/
template<typename Future>
class callback {
public:
typedef void result_type;
callback(Future& future) :
m_future_pimpl(wait_gateway::get_impl(future)) {
m_future_pimpl->mark_pending();
}
typedef BOOST_DEDUCED_TYPENAME
Future::tuple_type tuple_type;
typedef BOOST_DEDUCED_TYPENAME
Future::tuple_traits_type tuple_traits_type;
/*
* By default a callback is one shot only.
* By calling this method you can revive a
* callback for another shot.
* You must guaranee that the future
* is still alive.
*/
void revive() {
m_future_pimpl->mark_pending();
}
#define BOOST_COROUTINE_gen_argn_type(z, n, unused) \
typedef BOOST_DEDUCED_TYPENAME \
tuple_traits_type:: \
template at<n>::type \
BOOST_PP_CAT(BOOST_PP_CAT(arg, n), _type); \
/**/
BOOST_PP_REPEAT(BOOST_COROUTINE_ARG_MAX,
BOOST_COROUTINE_gen_argn_type,
~);
#define BOOST_COROUTINE_param_with_default(z, n, type_prefix) \
BOOST_DEDUCED_TYPENAME call_traits \
<BOOST_PP_CAT(BOOST_PP_CAT(type_prefix, n), _type)> \
::param_type \
BOOST_PP_CAT(arg, n) = \
BOOST_PP_CAT(BOOST_PP_CAT(type_prefix, n), _type)() \
/**/
void operator()
(BOOST_PP_ENUM
(BOOST_COROUTINE_ARG_MAX,
BOOST_COROUTINE_param_with_default,
arg)) {
m_future_pimpl->assign(tuple_type
(BOOST_PP_ENUM_PARAMS
(BOOST_COROUTINE_ARG_MAX, arg)));
}
private:
BOOST_DEDUCED_TYPENAME
Future::impl_pointer
m_future_pimpl;
};
#undef BOOST_COROUTINE_gen_future_assigner
#undef BOOST_COROUTINE_tuple_param_n
template<typename Future, typename Functor, typename CoroutineSelf>
Future call_impl(Functor fun, const CoroutineSelf& coro_self) {
Future future(coro_self);
fun(callback<Future>(future));
return future;
}
} } }
#endif

View File

@@ -0,0 +1,416 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_CONTEXT_IMPL_HPP_20060810
#define BOOST_COROUTINE_CONTEXT_IMPL_HPP_20060810
/*
* Currently asio can, in some cases. call copy constructors and
* operator= from different threads, even if in the
* one-thread-per-service model. (i.e. from the resolver thread)
* This will be corrected in future versions, but for now
* we will play it safe and use an atomic count. The overhead shouldn't
* be big.
*/
#define BOOST_COROUTINE_USE_ATOMIC_COUNT
#ifdef BOOST_COROUTINE_USE_ATOMIC_COUNT
# include <boost/detail/atomic_count.hpp>
#endif
#include <cstddef>
#include <algorithm> //for swap
#include <boost/coroutine/detail/swap_context.hpp> //for swap hints
#include <boost/intrusive_ptr.hpp>
#include <boost/coroutine/exception.hpp>
#include <boost/coroutine/detail/noreturn.hpp>
namespace boost { namespace coroutines { namespace detail {
const std::ptrdiff_t default_stack_size = -1;
template<typename ContextImpl>
class context_base : public ContextImpl {
public:
typedef ContextImpl context_impl;
typedef context_base<context_impl> type;
typedef boost::intrusive_ptr<type> pointer;
typedef void deleter_type(const type*);
template<typename Derived>
context_base(Derived& derived,
std::ptrdiff_t stack_size) :
context_impl(derived, stack_size),
m_counter(0),
m_deleter(&deleter<Derived>),
m_state(ctx_ready),
m_exit_state(ctx_exit_not_requested),
m_exit_status(ctx_not_exited),
m_wait_counter(0),
m_operation_counter(0),
m_type_info(0) {}
friend
void intrusive_ptr_add_ref(type * ctx) {
ctx->acquire();
}
friend
void intrusive_ptr_release(type * ctx) {
ctx->release();
}
bool unique() const {
return count() == 1;
}
std::size_t count() const {
return m_counter;
}
void acquire() const {
++m_counter;
}
void release() const {
BOOST_ASSERT(m_counter);
if(--m_counter == 0) {
m_deleter(this);
}
}
void count_down() throw() {
BOOST_ASSERT(m_operation_counter) ;
--m_operation_counter;
}
void count_up() throw() {
++m_operation_counter;
}
// return true if there are operations pending.
int pending() const {
return m_operation_counter;
}
/*
* A signal may occur only when a context is
* not running (is delivered sinchrononously).
* This means that state MUST NOT be busy.
* It may be ready or waiting.
* returns 'ready()'.
* Nothrow.
*/
bool signal () throw() {
BOOST_ASSERT(!running() && !exited());
BOOST_ASSERT(m_wait_counter) ;
--m_wait_counter;
if(!m_wait_counter && m_state == ctx_waiting)
m_state = ctx_ready;
return ready();
}
/*
* Wake up a waiting context.
* Similar to invoke(), but *does not
* throw* if the coroutine exited normally
* or entered the wait state.
* It *does throw* if the coroutine
* exited abnormally.
* Return: false if invoke() would have thrown,
* true otherwise.
*
*/
bool wake_up() {
BOOST_ASSERT(ready());
do_invoke();
// TODO: could use a binary 'or' here to eliminate
// shortcut evaluation (and a branch), but maybe the compiler is
// smart enough to do it anyway as there are no side effects.
if(m_exit_status || m_state == ctx_waiting) {
if(m_state == ctx_waiting)
return false;
if(m_exit_status == ctx_exited_return)
return true;
if(m_exit_status == ctx_exited_abnormally) {
std::type_info const * tinfo =0;
std::swap(m_type_info, tinfo);
throw abnormal_exit(tinfo?*tinfo: typeid(unknown_exception_tag));
} else if(m_exit_status == ctx_exited_exit)
return false;
else {
BOOST_ASSERT(0 && "unkonw exit status");
}
}
return true;
}
/*
* Returns true if the context is runnable.
*/
bool ready() const {
return m_state == ctx_ready;
}
/*
* Returns true if the context is in wait
* state.
*/
bool waiting() const {
return m_state == ctx_waiting;
}
bool running() const {
return m_state == ctx_running;
}
bool exited() const {
return m_state == ctx_exited;
}
// Resume coroutine.
// Pre: The coroutine must be ready.
// Post: The coroutine relinquished control. It might be ready, waiting
// or exited.
// Throws:- 'waiting' if the coroutine entered the wait state,
// - 'coroutine_exited' if the coroutine exited by an uncaught
// 'exit_exception'.
// - 'abnormal_exit' if the coroutine was exited by another
// uncaught exception.
// Note, it guarantees that the coroutine is resumed. Can throw only
// on return.
void invoke() {
BOOST_ASSERT(ready());
do_invoke();
// TODO: could use a bynary or here to eliminate
// shortcut evaluation (and a branch), but maybe the compiler is
// smart enough to do it anyway as there are no side effects.
if(m_exit_status || m_state == ctx_waiting) {
if(m_state == ctx_waiting)
throw waiting();
if(m_exit_status == ctx_exited_return)
return;
if(m_exit_status == ctx_exited_abnormally) {
std::type_info const * tinfo =0;
std::swap(m_type_info, tinfo);
throw abnormal_exit(tinfo?*tinfo: typeid(unknown_exception_tag));
} else if(m_exit_status == ctx_exited_exit)
throw coroutine_exited();
else {
BOOST_ASSERT(0 && "unkonw exit status");
}
}
}
// Put coroutine in ready state and relinquish control
// to caller until resumed again.
// Pre: Coroutine is running.
// Exit not pending.
// Operations not pending.
// Post: Coroutine is running.
// Throws: exit_exception, if exit is pending *after* it has been
// resumed.
void yield() {
BOOST_ASSERT(m_exit_state < ctx_exit_signaled); //prevent infinite loops
BOOST_ASSERT(running());
BOOST_ASSERT(!pending());
m_state = ctx_ready;
do_yield();
BOOST_ASSERT(running());
check_exit_state();
}
//
// If n > 0, put the coroutine in the wait state
// then relinquish control to caller.
// If n = 0 do nothing.
// The coroutine will remain in the wait state until
// is signaled 'n' times.
// Pre: 0 <= n < pending()
// Coroutine is running.
// Exit not pending.
// Post: Coroutine is running.
// The coroutine has been signaled 'n' times unless an exit
// has been signaled.
// Throws: exit_exception.
// FIXME: currently there is a BIG problem. A coroutine cannot
// be exited as long as there are futures pending.
// The exit_exception would cause the future to be destroyed and
// an assertion to be generated. Removing an assertion is not a
// solution because we would leak the coroutine impl. The callback
// bound to the future in fact hold a refrence to it. If the coroutine
// is exited the callback cannot be called.
void wait(int n) {
BOOST_ASSERT(!(n<0));
BOOST_ASSERT(m_exit_state < ctx_exit_signaled); //prevent infinite loop
BOOST_ASSERT(running());
BOOST_ASSERT(!(pending() < n));
if(n == 0) return;
m_wait_counter = n;
m_state = ctx_waiting;
do_yield();
BOOST_ASSERT(m_state == ctx_running);
check_exit_state();
BOOST_ASSERT(m_wait_counter == 0);
}
// Throws: exit_exception.
void yield_to(context_base& to) {
BOOST_ASSERT(m_exit_state < ctx_exit_signaled); //prevent infinite loops
BOOST_ASSERT(m_state == ctx_running);
BOOST_ASSERT(to.ready());
BOOST_ASSERT(!to.pending());
std::swap(m_caller, to.m_caller);
std::swap(m_state, to.m_state);
swap_context(*this, to, detail::yield_to_hint());
BOOST_ASSERT(m_state == ctx_running);
check_exit_state();
}
// Cause this coroutine to exit.
// Can only be called on a ready coroutine.
// Cannot be called if there are pending operations.
// It follws that cannot be called from 'this'.
// Nothrow.
void exit() throw(){
BOOST_ASSERT(!pending());
BOOST_ASSERT(ready()) ;
if(m_exit_state < ctx_exit_pending)
m_exit_state = ctx_exit_pending;
do_invoke();
BOOST_ASSERT(exited()); //at this point the coroutine MUST have exited.
}
// Always throw exit_exception.
// Never returns from standard control flow.
BOOST_COROUTINE_NORETURN(void exit_self()) {
BOOST_ASSERT(!pending());
BOOST_ASSERT(running());
m_exit_state = ctx_exit_pending;
throw exit_exception();
}
// Nothrow.
~context_base() throw() {
BOOST_ASSERT(!running());
try {
if(!exited())
exit();
BOOST_ASSERT(exited());
} catch(...) {}
}
protected:
// global coroutine state
enum context_state {
ctx_running, // context running.
ctx_ready, // context at yield point.
ctx_waiting, // context waiting for events.
ctx_exited // context is finished.
};
// exit request state
enum context_exit_state {
ctx_exit_not_requested, // exit not requested.
ctx_exit_pending, // exit requested.
ctx_exit_signaled, // exit request delivered.
};
// exit status
enum context_exit_status {
ctx_not_exited,
ctx_exited_return, // process exited by return.
ctx_exited_exit, // process exited by exit().
ctx_exited_abnormally // process exited uncleanly.
};
// Cause the coroutine to exit if
// a exit request is pending.
// Throws: exit_exception if an exit request is pending.
void check_exit_state() {
BOOST_ASSERT(running());
if(!m_exit_state) return;
throw exit_exception();
}
// Nothrow.
void do_return(context_exit_status status, std::type_info const* info) throw() {
BOOST_ASSERT(status != ctx_not_exited);
BOOST_ASSERT(m_state == ctx_running);
m_type_info = info;
m_state = ctx_exited;
m_exit_status = status;
do_yield();
}
private:
// Nothrow.
void do_yield() throw() {
swap_context(*this, m_caller, detail::yield_hint());
}
// Nothrow.
void do_invoke() throw (){
BOOST_ASSERT(ready() || waiting());
m_state = ctx_running;
swap_context(m_caller, *this, detail::invoke_hint());
}
template<typename ActualCtx>
static void deleter (const type* ctx){
delete static_cast<ActualCtx*>(const_cast<type*>(ctx));
}
typedef typename context_impl::context_impl_base ctx_type;
ctx_type m_caller;
mutable
#ifndef BOOST_COROUTINE_USE_ATOMIC_COUNT
std::size_t
#else
boost::detail::atomic_count
#endif
m_counter;
deleter_type * m_deleter;
context_state m_state;
context_exit_state m_exit_state;
context_exit_status m_exit_status;
int m_wait_counter;
int m_operation_counter;
// This is used to generate a meaningful exception trace.
std::type_info const* m_type_info;
};
} } }
#endif

View File

@@ -0,0 +1,285 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_CONTEXT_LINUX_HPP_20060601
#define BOOST_COROUTINE_CONTEXT_LINUX_HPP_20060601
#if defined(__GNUC__) && defined(__i386__) && !defined(BOOST_COROUTINE_NO_ASM)
#include <cstdlib>
#include <cstddef>
#include <boost/coroutine/detail/posix_utility.hpp>
#include <boost/coroutine/detail/swap_context.hpp>
#include <boost/assert.hpp>
/*
* Defining BOOST_COROUTINE_INLINE_ASM will enable the inlin3
* assembler verwsion of swapcontext_stack.
* The inline asm, with all required clobber flags, is usually no faster
* than the out-of-line function, and it is not yet clear if
* it is always reliable (i.e. if the compiler always saves the correct
* registers). FIXME: it is currently missing at least MMX and XMM registers in
* the clobber list.
*/
/*
* Defining BOOST_COROUTINE_NO_SEPARATE_CALL_SITES will disable separate
* invoke, yield and yield_to swap_context functions. Separate calls sites
* increase performance by 25% at least on P4 for invoke+yield back loops
* at the cost of a slightly higher instruction cache use and is thus enabled by
* default.
*/
//#define BOOST_COROUTINE_NO_SEPARATE_CALL_SITES
//#define BOOST_COROUTINE_INLINE_ASM
#ifndef BOOST_COROUTINE_INLINE_ASM
extern "C" void swapcontext_stack (void***, void**) throw() __attribute((regparm(2)));
extern "C" void swapcontext_stack2 (void***, void**) throw() __attribute((regparm(2)));
extern "C" void swapcontext_stack3 (void***, void**) throw() __attribute((regparm(2)));
#else
# if 1
void
inline
swapcontext_stack(void***from_sp, void**to_sp) throw() {
asm volatile
("\n\t pushl %%ebp"
"\n\t pushl %[from]"
"\n\t pushl %[to]"
"\n\t pushl $0f"
"\n\t movl %%esp, (%[from])"
"\n\t movl %[to], %%esp"
"\n\t popl %%ecx"
"\n\t jmp *%%ecx"
"\n0:\t popl %[to]"
"\n\t popl %[from]"
"\n\t popl %%ebp"
::
[from] "a" (from_sp),
[to] "d" (to_sp)
:
"cc",
"%ecx",
"%ebx",
"%edi",
"%esi",
"%st",
"%st(1)",
"%st(2)",
"%st(3)",
"%st(4)",
"%st(5)",
"%st(6)",
"%st(7)",
"memory"
);
}
# else
typedef void (*fun_type)(void***from_sp, void**to_sp)
__attribute((regparm(2)));
fun_type get_swapper();// __attribute__((pure));
inline
fun_type get_swapper(){
fun_type ptr;
asm volatile("mov $0f, %[result]"
"\n\t jmp 1f"
"\n0:"
//"\n\t movl 16(%%edx), %%ecx"
"\n\t pushl %%ebp"
"\n\t pushl %%ebx"
"\n\t pushl %%esi"
"\n\t pushl %%edi"
"\n\t movl %%esp, (%%eax)"
"\n\t movl %%edx, %%esp"
"\n\t popl %%edi"
"\n\t popl %%esi"
"\n\t popl %%ebx"
"\n\t popl %%ebp"
"\n\t popl %%ecx"
"\n\t jmp *%%ecx"
"\n1:"
:
[result] "=g" (ptr)
:
);
return ptr;
};
void
inline
swapcontext_stack(void***from_sp, void**to_sp) throw() {
fun_type ptr = get_swapper();
ptr(from_sp, to_sp);
}
# endif
void
inline
swapcontext_stack2(void***from_sp, void**to_sp) throw() {
swapcontext_stack(from_sp, to_sp);
}
#endif
namespace boost { namespace coroutines { namespace detail {
namespace oslinux {
template<typename T>
void trampoline(T* fun);
template<typename T>
inline
void
trampoline(T * fun) {
(*fun)();
std::abort();
}
class ia32_gcc_context_impl_base {
public:
ia32_gcc_context_impl_base() {};
void prefetch() const {
__builtin_prefetch (m_sp, 1, 3);
__builtin_prefetch (m_sp, 0, 3);
__builtin_prefetch ((void**)m_sp+64/4, 1, 3);
__builtin_prefetch ((void**)m_sp+64/4, 0, 3);
__builtin_prefetch ((void**)m_sp+32/4, 1, 3);
__builtin_prefetch ((void**)m_sp+32/4, 0, 3);
__builtin_prefetch ((void**)m_sp-32/4, 1, 3);
__builtin_prefetch ((void**)m_sp-32/4, 0, 3);
__builtin_prefetch ((void**)m_sp-64/4, 1, 3);
__builtin_prefetch ((void**)m_sp-64/4, 0, 3);
}
/**
* Free function. Saves the current context in @p from
* and restores the context in @p to.
* @note This function is found by ADL.
*/
friend
void
swap_context(ia32_gcc_context_impl_base& from,
ia32_gcc_context_impl_base const& to,
default_hint) {
to.prefetch();
swapcontext_stack(&from.m_sp, to.m_sp);
}
#ifndef BOOST_COROUTINE_NO_SEPARATE_CALL_SITES
friend
void
swap_context(ia32_gcc_context_impl_base& from,
ia32_gcc_context_impl_base const& to,
yield_hint) {
to.prefetch();
swapcontext_stack2(&from.m_sp, to.m_sp);
}
friend
void
swap_context(ia32_gcc_context_impl_base& from,
ia32_gcc_context_impl_base const& to,
yield_to_hint) {
to.prefetch();
swapcontext_stack2(&from.m_sp, to.m_sp);
}
#endif
protected:
void ** m_sp;
};
class ia32_gcc_context_impl : public ia32_gcc_context_impl_base{
public:
enum {default_stack_size = 64*1024};
typedef ia32_gcc_context_impl_base context_impl_base;
ia32_gcc_context_impl() :
m_stack(0) {}
/**
* Create a context that on restore invokes Functor on
* a new stack. The stack size can be optionally specified.
*/
template<typename Functor>
ia32_gcc_context_impl(Functor& cb, std::ptrdiff_t stack_size = -1) :
m_stack_size(stack_size == -1? default_stack_size: stack_size),
m_stack(posix::alloc_stack(m_stack_size)) {
m_sp = ((void**)m_stack + (m_stack_size/sizeof(void*))),
BOOST_ASSERT(m_stack);
typedef void fun(Functor*);
fun * funp = trampoline;
#ifndef BOOST_COROUTINE_INLINE_ASM
*--m_sp = &cb; // parm 0 of trampoline;
*--m_sp = 0; // dummy return address for trampoline
*--m_sp = (void*) funp ;// return addr (here: start addr) NOTE: the unsafe cast is safe on IA32
*--m_sp = 0; // ebp
*--m_sp = 0; // ebx
*--m_sp = 0; // esi
*--m_sp = 0; // edi
#else
*--m_sp = &cb; // parm 0 of trampoline;
*--m_sp = 0; // dummy return address for trampoline
*--m_sp = (void*) funp ;// return addr (here: start addr) NOTE: the unsafe cast is safe on IA32
#endif
}
~ia32_gcc_context_impl() {
if(m_stack)
posix::free_stack(m_stack, m_stack_size);
}
private:
std::ptrdiff_t m_stack_size;
void * m_stack;
};
typedef ia32_gcc_context_impl context_impl;
}
} } }
#elif defined(__linux)
/**
* For all other linux systems use the standard posix implementation.
*/
#include <boost/coroutine/detail/context_posix.hpp>
namespace boost { namespace coroutines { namespace detail { namespace oslinux {
typedef posix::context_impl context_impl;
} } } }
#else
#error This header can only be included when compiling for linux systems.
#endif
#endif

View File

@@ -0,0 +1,231 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_CONTEXT_POSIX_HPP_20060601
#define BOOST_COROUTINE_CONTEXT_POSIX_HPP_20060601
// NOTE (per http://lists.apple.com/archives/darwin-dev/2008/Jan/msg00232.html):
// > Why the bus error? What am I doing wrong?
// This is a known issue where getcontext(3) is writing past the end of the
// ucontext_t struct when _XOPEN_SOURCE is not defined (rdar://problem/5578699 ).
// As a workaround, define _XOPEN_SOURCE before including ucontext.h.
#if defined(__APPLE__) && ! defined(_XOPEN_SOURCE)
#define _XOPEN_SOURCE
// However, the above #define will only affect <ucontext.h> if it has not yet
// been #included by something else!
#if defined(_STRUCT_UCONTEXT)
#error You must #include coroutine headers before anything that #includes <ucontext.h>
#endif
#endif
#include <boost/config.hpp>
#include <boost/assert.hpp>
#if defined(_XOPEN_UNIX) && defined(_XOPEN_VERSION) && _XOPEN_VERSION >= 500
// OS X 10.4 -- despite passing the test above -- doesn't support
// swapcontext() et al. Use GNU Pth workalike functions.
#if defined(__APPLE__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1050)
#include "pth/pth.h"
#include <cerrno>
namespace boost { namespace coroutines { namespace detail {
namespace posix { namespace pth {
inline int check(int rc)
{
// The makecontext() functions return zero for success, nonzero for
// error. The Pth library returns TRUE for success, FALSE for error,
// with errno set to the nonzero error in the latter case. Map the Pth
// returns to ucontext style.
return rc? 0 : errno;
}
}}}}}
#define BOOST_CORO_POSIX_IMPL "Pth implementation"
#define BOOST_CORO_DECLARE_CONTEXT(name) pth_uctx_t name
#define BOOST_CORO_CREATE_CONTEXT(ctx) \
boost::coroutines::detail::posix::pth::check(pth_uctx_create(&(ctx)))
#define BOOST_CORO_MAKE_CONTEXT(ctx, stack, size, startfunc, startarg, exitto) \
/* const sigset_t* sigmask = NULL: we don't expect per-context signal masks */ \
boost::coroutines::detail::posix::pth::check(pth_uctx_make(*(ctx), static_cast<char*>(stack), (size), NULL, (startfunc), (startarg), (exitto)))
#define BOOST_CORO_SWAP_CONTEXT(from, to) \
boost::coroutines::detail::posix::pth::check(pth_uctx_switch(*(from), *(to)))
#define BOOST_CORO_DESTROY_CONTEXT(ctx) \
boost::coroutines::detail::posix::pth::check(pth_uctx_destroy(ctx))
#else // generic Posix platform (e.g. OS X >= 10.5)
/*
* makecontext based context implementation. Should be available on all
* SuSv2 compliant UNIX systems.
* NOTE: this implementation is not
* optimal as the makecontext API saves and restore the signal mask.
* This requires a system call for every context switch that really kills
* performance. Still is very portable and guaranteed to work.
* NOTE2: makecontext and friends are declared obsolescent in SuSv3, but
* it is unlikely that they will be removed any time soon.
*/
#include <ucontext.h>
#include <cstddef> // ptrdiff_t
namespace boost { namespace coroutines { namespace detail {
namespace posix { namespace ucontext {
inline int make_context(::ucontext_t* ctx, void* stack, std::ptrdiff_t size,
void (*startfunc)(void*), void* startarg, ::ucontext_t* exitto = NULL)
{
int error = ::getcontext(ctx);
if (error)
return error;
ctx->uc_stack.ss_sp = stack;
ctx->uc_stack.ss_size = size;
ctx->uc_link = exitto;
typedef void (*ctx_main)();
//makecontext can't fail.
::makecontext(ctx,
(ctx_main)(startfunc),
1,
startarg);
return 0;
}
}}}}}
#define BOOST_CORO_POSIX_IMPL "ucontext implementation"
#define BOOST_CORO_DECLARE_CONTEXT(name) ::ucontext_t name
#define BOOST_CORO_CREATE_CONTEXT(ctx) /* nop */
#define BOOST_CORO_MAKE_CONTEXT(ctx, stack, size, startfunc, startarg, exitto) \
boost::coroutines::detail::posix::ucontext::make_context(ctx, stack, size, startfunc, startarg, exitto)
#define BOOST_CORO_SWAP_CONTEXT(pfrom, pto) ::swapcontext((pfrom), (pto))
#define BOOST_CORO_DESTROY_CONTEXT(ctx) /* nop */
#endif // generic Posix platform
#include <signal.h> // SIGSTKSZ
#include <boost/noncopyable.hpp>
#include <boost/coroutine/exception.hpp>
#include <boost/coroutine/detail/posix_utility.hpp>
#include <boost/coroutine/detail/swap_context.hpp>
namespace boost { namespace coroutines { namespace detail {
namespace posix {
/*
* Posix implementation for the context_impl_base class.
* @note context_impl is not required to be consistent
* If not initialized it can only be swapped out, not in
* (at that point it will be initialized).
*
*/
class ucontext_context_impl_base {
public:
ucontext_context_impl_base()
{
BOOST_CORO_CREATE_CONTEXT(m_ctx);
}
~ucontext_context_impl_base()
{
BOOST_CORO_DESTROY_CONTEXT(m_ctx);
}
private:
/*
* Free function. Saves the current context in @p from
* and restores the context in @p to.
*/
friend
void
swap_context(ucontext_context_impl_base& from,
const ucontext_context_impl_base& to,
default_hint) {
int error = BOOST_CORO_SWAP_CONTEXT(&from.m_ctx, &to.m_ctx);
(void)error;
BOOST_ASSERT(error == 0);
}
protected:
BOOST_CORO_DECLARE_CONTEXT(m_ctx);
};
class ucontext_context_impl :
public ucontext_context_impl_base,
private boost::noncopyable {
public:
typedef ucontext_context_impl_base context_impl_base;
enum {default_stack_size = 64*1024};
/**
* Create a context that on restore invokes Functor on
* a new stack. The stack size can be optionally specified.
*/
template<typename Functor>
explicit
ucontext_context_impl(Functor& cb, std::ptrdiff_t stack_size) :
m_stack_size(stack_size == -1? default_stack_size: stack_size),
m_stack(alloc_stack(m_stack_size)) {
BOOST_ASSERT(m_stack);
typedef void cb_type(Functor*);
cb_type * cb_ptr = &trampoline<Functor>;
int error = BOOST_CORO_MAKE_CONTEXT(&m_ctx, m_stack, m_stack_size,
(void (*)(void*))(cb_ptr), &cb, NULL);
(void)error;
BOOST_ASSERT(error == 0);
}
~ucontext_context_impl() {
if(m_stack)
free_stack(m_stack, m_stack_size);
}
private:
// declare m_stack_size first so we can use it to initialize m_stack
std::ptrdiff_t m_stack_size;
void * m_stack;
};
typedef ucontext_context_impl context_impl;
}
} } }
#else
/**
* This #else clause is essentially unchanged from the original Google Summer
* of Code version of Boost.Coroutine, which comments:
* "Context swapping can be implemented on most posix systems lacking *context
* using the sigaltstack+longjmp trick."
* This is in fact what the (highly portable) Pth library does, so if you
* encounter such a system, perhaps the best approach would be to twiddle the
* #if logic in this header to use the pth.h implementation above.
*/
#error No context implementation for this POSIX system.
#endif
#endif

View File

@@ -0,0 +1,181 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_CONTEXT_WINDOWS_HPP_20060625
#define BOOST_COROUTINE_CONTEXT_WINDOWS_HPP_20060625
// This _WIN32_WINNT kludge is necessary to make winbase.h publish the Fiber API.
// 0x0400 makes CreateFiber(), etc., visible
// 0x0501 makes ConvertThreadToFiber() visible
// 0x0600 makes IsThreadAFiber() visible
// And no, I have no idea why this symbol isn't being set appropriately by
// the build environment.
#define WIN32_LEAN_AND_MEAN
#define _WIN32_WINNT 0x0600
// The above #define will only affect <windows.h> if it has not yet been
// #included by something else!
#if defined(WINBASEAPI)
#error You must #include coroutine headers before anything that #includes <windows.h>
#endif
#include <windows.h>
#include <winnt.h>
#include <boost/config.hpp>
#include <boost/assert.hpp>
#include <boost/noncopyable.hpp>
#include <boost/coroutine/exception.hpp>
#include <boost/coroutine/detail/swap_context.hpp>
namespace boost {namespace coroutines {namespace detail{
namespace windows {
typedef LPVOID fiber_ptr;
/*
* This number (0x1E00) has been sighted in the wild (at least on windows XP systems)
* as return value from GetCurrentFiber() on non fibrous threads. This is sowehow related
* to OS/2 where the current fiber pointer is overloaded as a version field.
* On non-NT systems, 0 is returned.
*/
const fiber_ptr fiber_magic = reinterpret_cast<fiber_ptr>(0x1E00);
/*
* Return true if current thread is a fiber.
* FIXME: on longhorn shoud use IsThreadAFiber
*/
inline
bool is_fiber() {
fiber_ptr current = GetCurrentFiber();
return current != 0 && current != fiber_magic;
}
/*
* Windows implementation for the context_impl_base class.
* @note context_impl is not required to be consistent
* If not initialized it can only be swapped out, not in
* (at that point it will be initialized).
*/
class fibers_context_impl_base {
public:
/**
* Create an empty context.
* An empty context cannot be restored from,
* but can be saved in.
*/
fibers_context_impl_base() :
m_ctx(0) {}
/*
* Free function. Saves the current context in @p from
* and restores the context in @p to. On windows the from
* parameter is ignored. The current context is saved on the
* current fiber.
* Note that if the current thread is not a fiber, it will be
* converted to fiber on the fly on call and unconverted before
* return. This is expensive. The user should convert the
* current thread to a fiber once on thread creation for better performance.
* Note that we can't leave the thread unconverted on return or else we
* will leak resources on thread destruction. Do the right thing by
* default.
*/
friend
void
swap_context(fibers_context_impl_base& from,
const fibers_context_impl_base& to,
default_hint) {
if(!is_fiber()) {
BOOST_ASSERT(from.m_ctx == 0);
from.m_ctx = ConvertThreadToFiber(0);
BOOST_ASSERT(from.m_ctx != 0);
SwitchToFiber(to.m_ctx);
BOOL result = ConvertFiberToThread();
BOOST_ASSERT(result);
(void)result;
from.m_ctx = 0;
} else {
bool call_from_main = from.m_ctx == 0;
if(call_from_main)
from.m_ctx = GetCurrentFiber();
SwitchToFiber(to.m_ctx);
if(call_from_main)
from.m_ctx = 0;
}
}
~fibers_context_impl_base() {}
protected:
explicit
fibers_context_impl_base(fiber_ptr ctx) :
m_ctx(ctx) {}
fiber_ptr m_ctx;
};
template<typename T>
inline
VOID CALLBACK
trampoline(LPVOID pv) {
T* fun = static_cast<T*>(pv);
BOOST_ASSERT(fun);
(*fun)();
}
class fibers_context_impl :
public fibers_context_impl_base,
private boost::noncopyable {
public:
typedef fibers_context_impl_base context_impl_base;
enum {default_stack_size = 64*1024};
/**
* Create a context that on restore inovkes Functor on
* a new stack. The stack size can be optionally specified.
*/
template<typename Functor>
explicit
fibers_context_impl(Functor& cb, std::ptrdiff_t stack_size) :
fibers_context_impl_base
(CreateFiber(stack_size== -1? 0 : stack_size,
static_cast<LPFIBER_START_ROUTINE>(&trampoline<Functor>),
static_cast<LPVOID>(&cb)))
{
BOOST_ASSERT(m_ctx);
}
~fibers_context_impl() {
DeleteFiber(m_ctx);
}
private:
};
typedef fibers_context_impl context_impl;
}
} } }
#endif

View File

@@ -0,0 +1,103 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_COROUTINE_ACCESSOR_HPP_20060709
#define BOOST_COROUTINE_DETAIL_COROUTINE_ACCESSOR_HPP_20060709
#include <boost/utility/in_place_factory.hpp>
namespace boost { namespace coroutines { namespace detail {
/*
* This is a private interface used for coroutine
* implementation.
*/
struct init_from_impl_tag{};
struct coroutine_accessor {
// Initialize coroutine from implementation type.
// used by the in_place_assing in place factory.
template<typename Coroutine, typename Ctx>
static
void construct(Ctx * src, void * address) {
new (address) Coroutine(src, init_from_impl_tag());
}
template<typename Coroutine>
static
void acquire(Coroutine& x) {
x.acquire();
}
template<typename Coroutine>
static
void release(Coroutine& x) {
x.release();
}
template<typename Ctx>
struct in_place_assign : boost::in_place_factory_base {
in_place_assign(Ctx * ctx) :
m_ctx(ctx) {}
template<typename Coroutine>
void apply(void * memory) const {
construct<Coroutine>(m_ctx, memory);
}
Ctx * m_ctx;
};
template<typename Ctx>
static
in_place_assign<Ctx>
in_place(Ctx * ctx) {
return in_place_assign<Ctx>(ctx);
}
template<typename Coroutine>
static
typename Coroutine::impl_ptr
get_impl(Coroutine& x) {
return x.get_impl();
}
template<typename Coroutine>
static
typename Coroutine::impl_type *
pilfer_impl(Coroutine& x) {
return x.pilfer_impl();
}
template<typename Coroutine>
static
std::size_t
count(const Coroutine& x) {
return x.count();
}
};
} } }
#endif

View File

@@ -0,0 +1,276 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_COROUTINE_IMPL_HPP_20060601
#define BOOST_COROUTINE_COROUTINE_IMPL_HPP_20060601
#if defined(_MSC_VER)
#pragma warning (push)
#pragma warning (disable: 4355) //this used in base member initializer
#endif
#include <cstddef>
#include <boost/optional.hpp>
#include <boost/coroutine/detail/argument_unpacker.hpp>
#include <boost/coroutine/detail/coroutine_accessor.hpp>
#include <boost/coroutine/detail/context_base.hpp>
namespace boost { namespace coroutines { namespace detail {
// This class augment the contest_base class with
// the coroutine signature type.
// This is mostly just a place to put
// typesafe argument and result type pointers.
template<typename CoroutineType, typename ContextImpl>
class coroutine_impl:
public context_base<ContextImpl>
{
public:
template<typename DerivedType, typename ResultType>
friend class add_result;
typedef ContextImpl context_impl;
typedef CoroutineType coroutine_type;
typedef coroutine_impl<coroutine_type, context_impl> type;
typedef context_base<context_impl> context_base;
typedef typename coroutine_type::arg_slot_type arg_slot_type;
typedef typename coroutine_type::result_type result_type;
typedef typename coroutine_type::result_slot_type result_slot_type;
typedef boost::intrusive_ptr<type> pointer;
template<typename DerivedType>
coroutine_impl(DerivedType * this_, std::ptrdiff_t stack_size) :
context_base(*this_, stack_size),
m_arg(0),
m_result(0){}
arg_slot_type * args() {
BOOST_ASSERT(m_arg);
return m_arg;
};
result_slot_type * result() {
BOOST_ASSERT(m_result);
BOOST_ASSERT(*m_result);
return *this->m_result;
}
template<typename Functor>
static inline
pointer create(Functor, std::ptrdiff_t);
void bind_args(arg_slot_type* arg) {
m_arg = arg;
}
void bind_result(result_slot_type* res) {
// This used to be unconditional. But m_result isn't always valid.
if (m_result) {
*m_result = res;
}
}
// Another level of indirecition is needed to handle
// yield_to correctly.
void bind_result_pointer(result_slot_type** resp) {
m_result = resp;
}
result_slot_type** result_pointer() {
return m_result;
}
/// This helper class packages data/logic originally found inline in
/// coroutine::call_impl() and call_impl_nothrow(), also
/// coroutine_impl::run().
class local_result_slot_ptr
{
public:
local_result_slot_ptr(pointer pimpl):
m_pimpl(pimpl),
m_ptr(NULL)
{
m_pimpl->bind_result_pointer(&m_ptr);
}
~local_result_slot_ptr()
{
// In the original use case, a coroutine could only be resumed by
// calling coroutine::operator() again, which would rebind the
// result pointer to a new valid value. But with the introduction
// of futures, it's possible to suspend a coroutine by waiting on
// a future object -- thus destroying the local result_slot_type*
// -- then resume that coroutine by calling the future's callback,
// bypassing coroutine::operator(). This used to leave an old,
// invalid result pointer in effect. Subsequent coroutine exit
// wrote through that pointer, munging a word of stack. Now we
// make a point of setting the bound result pointer NULL when the
// result_slot_type* to which it pointed vanishes, so that any
// attempt to dereference it will at least self-identify --
// instead of producing arbitrary undefined behavior.
m_pimpl->bind_result_pointer(NULL);
}
private:
pointer m_pimpl;
result_slot_type* m_ptr;
};
// This function must be called only for void
// coroutines. It wakes up the coroutine.
// Entering the wait state does not cause this
// method to throw.
void run() {
arg_slot_type void_args;
// This dummy binding is required because
// do_call expect args() and result()
// to return a non NULL result.
bind_args(&void_args);
local_result_slot_pointer(this);
this->wake_up();
}
protected:
boost::optional<result_slot_type> m_result_last;
private:
arg_slot_type * m_arg;
result_slot_type ** m_result;
};
// This type augment coroutine_impl type with the type of the stored
// functor. The type of this object is erased right after construction
// when it is assigned to a pointer to coroutine_impl. A deleter is
// passed down to make it sure that the correct derived type is deleted.
template<typename FunctorType, typename CoroutineType, typename ContextImpl>
class coroutine_impl_wrapper :
public coroutine_impl<CoroutineType, ContextImpl> {
public:
typedef coroutine_impl_wrapper<FunctorType, CoroutineType, ContextImpl>
type;
typedef CoroutineType coroutine_type;
typedef typename CoroutineType::result_type result_type;
typedef coroutine_impl<CoroutineType, ContextImpl> super_type;
typedef FunctorType functor_type;
coroutine_impl_wrapper(functor_type f, std::ptrdiff_t stack_size) :
super_type(this, stack_size),
m_fun(f){}
void operator()() {
typedef typename super_type::context_exit_status
context_exit_status;
context_exit_status status = super_type::ctx_exited_return;
std::type_info const* tinfo = 0;
try {
this->check_exit_state();
do_call<result_type>();
} catch (const exit_exception&) {
status = super_type::ctx_exited_exit;
} catch (std::exception const& e) {
status = super_type::ctx_exited_abnormally;
tinfo = &typeid(e);
} catch (...) {
status = super_type::ctx_exited_abnormally;
}
this->do_return(status, tinfo);
}
public:
//GCC workaround as per enable_if docs
template <int> struct dummy { dummy(int) {} };
/*
* Implementation for operator()
* This is for void result types.
* Can throw if m_fun throws. At least it can throw exit_exception.
*/
template<typename ResultType>
typename boost::enable_if<boost::is_void<ResultType> >::type
do_call(dummy<0> = 0) {
BOOST_ASSERT(this->count() > 0);
typedef BOOST_DEDUCED_TYPENAME
coroutine_type::self self_type;
boost::optional<self_type> self (coroutine_accessor::in_place(this));
detail::unpack_ex
(m_fun,
*self,
*this->args(),
detail::trait_tag<typename coroutine_type::arg_slot_traits>());
typedef BOOST_DEDUCED_TYPENAME coroutine_type::result_slot_type
result_slot_type;
// In this particulare case result_slot_type is guaranteed to be
// default constructible.
this->m_result_last = result_slot_type();
this->bind_result(&*this->m_result_last);
}
// Same as above, but for non void result types.
template<typename ResultType>
typename boost::disable_if<boost::is_void<ResultType> >::type
do_call(dummy<1> = 1) {
BOOST_ASSERT(this->count() > 0);
typedef BOOST_DEDUCED_TYPENAME
coroutine_type::self self_type;
boost::optional<self_type> self (coroutine_accessor::in_place(this));
typedef BOOST_DEDUCED_TYPENAME coroutine_type::arg_slot_traits traits;
typedef BOOST_DEDUCED_TYPENAME coroutine_type::result_slot_type
result_slot_type;
this->m_result_last = boost::in_place(result_slot_type(detail::unpack_ex
(m_fun,
*self,
*this->args(),
detail::trait_tag<traits>())));
this->bind_result(&*this->m_result_last);
}
FunctorType m_fun;
};
template<typename CoroutineType, typename ContextImpl>
template<typename Functor>
inline
typename
coroutine_impl<CoroutineType, ContextImpl>::pointer
coroutine_impl<CoroutineType, ContextImpl>::
create(Functor f, std::ptrdiff_t stack_size = default_stack_size) {
return new coroutine_impl_wrapper<Functor, CoroutineType, ContextImpl>
(f, stack_size);
}
} } }
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
#endif

View File

@@ -0,0 +1,82 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_COROUTINE_TRAITS_HPP_20060613
#define BOOST_COROUTINE_DETAIL_COROUTINE_TRAITS_HPP_20060613
#include <boost/type_traits.hpp>
#include <boost/coroutine/tuple_traits.hpp>
#include <boost/coroutine/detail/yield_result_type.hpp>
namespace boost { namespace coroutines { namespace detail {
template<typename T>
struct as_tuple {
typedef typename T::as_tuple type;
};
// This trait class is used to compute
// all nested typedefs of coroutines given
// a signature in the form 'result_type(parm1, ... parmn)'.
template<typename Signature>
struct coroutine_traits {
private:
typedef BOOST_DEDUCED_TYPENAME boost::function_traits<Signature>::result_type
signature_result_type;
public:
typedef BOOST_DEDUCED_TYPENAME
boost::mpl::eval_if<is_tuple_traits<signature_result_type>,
as_tuple<signature_result_type>,
boost::mpl::identity<signature_result_type> >
::type result_type;
typedef BOOST_DEDUCED_TYPENAME
boost::mpl::eval_if<is_tuple_traits<signature_result_type>,
boost::mpl::identity<signature_result_type>,
boost::mpl::if_
<boost::is_same<signature_result_type, void>,
tuple_traits<>,
tuple_traits<signature_result_type> > >
::type result_slot_traits;
typedef BOOST_DEDUCED_TYPENAME result_slot_traits
::as_tuple result_slot_type;
typedef BOOST_DEDUCED_TYPENAME detail::make_tuple_traits
<typename detail::signature<Signature>::type >
::type arg_slot_traits;
typedef BOOST_DEDUCED_TYPENAME arg_slot_traits
::as_tuple arg_slot_type;
typedef BOOST_DEDUCED_TYPENAME arg_slot_traits
::as_result yield_result_type;
};
} } }
#endif

View File

@@ -0,0 +1,122 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DEFAULT_CONTEXT_IMPL_HPP_20060601
#define BOOST_COROUTINE_DEFAULT_CONTEXT_IMPL_HPP_20060601
#include <boost/config.hpp>
/*
ContextImpl concept documentation.
A ContextImpl holds a context plus its stack.
- ContextImpl must have constructor with the following signature:
template<typename Functor>
ContextImpl(Functor f, std::ptrdiff_t stack_size);
Preconditions:
f is a generic function object (support for function pointers
is not required.
stack_size is the size of the stack allocated
for the context. The stack_size is only an hint. If stack_size is -1
it should default to a sensible value.
Postconditions:
f is bound to this context in its own stack.
When the context is activated with swap_context for the first time
f is entered.
- ContextImpl destructor must properly dispose of the stack and perform
any other clean up action required.
- ContextImpl is not required to be DefaultConstructible nor Copyable.
- ContextImpl must expose the following typedef:
typedef unspecified-type context_impl_base;
ContextImpl must be convertible to context_impl_base.
context_impl_base must have conform to the ContextImplBase concept:
- DefaultConstructible. A default constructed ContextImplBase is in
an unitialized state.
A ContextImpl is an initialized ContextImplBase.
- ContextImplBase is Copyable. A copy of a ContextImplBase holds
The same informations as the original. Once a ContextImplBase
is used as an argument to swap_context, all its copies become stale.
(that is, only one copy of ContextImplBase can be used).
A ContextImpl cannot be sliced by copying it to a ContextImplBase.
- void swap_context(ContextImplBase& from,
const ContextImplBase& to)
This free function is called unqualified (via ADL).
Preconditions:
Its 'to' argument must be an initialized ContextImplBase.
Its 'from' argument may be an uninitialized ContextImplBase that
will be initialized by a swap_context.
Postconditions:
The current context is saved in the 'from' context, and the
'to' context is restored.
It is undefined behaviour if the 'to' argument is an invalid
(uninitialized) swapcontext.
A ContextImplBase is meant to be used when an empty temporary
context is needed to store the current context before
restoring a ContextImpl and no current context is
available. It could be possible to simply have ContextImpl
default constructible, but on destruciton it would need to
check if a stack has been allocated and would slow down the
fast invcation path. Also a stackful context could not be
make copiable.
*/
#if defined(__linux) || defined(linux) || defined(__linux__)
#include <boost/coroutine/detail/context_linux.hpp>
namespace boost { namespace coroutines { namespace detail {
typedef oslinux::context_impl default_context_impl;
} } }
#elif defined(_POSIX_VERSION)
#include <boost/coroutine/detail/context_posix.hpp>
namespace boost { namespace coroutines { namespace detail {
typedef posix::context_impl default_context_impl;
} } }
#elif defined(BOOST_WINDOWS)
#include <boost/coroutine/detail/context_windows.hpp>
namespace boost { namespace coroutines { namespace detail {
typedef windows::context_impl default_context_impl;
} } }
#else
#error No default_context_impl available for this system
#endif
#endif

View File

@@ -0,0 +1,61 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_FIX_RESULT_HPP_20060709
#define BOOST_COROUTINE_DETAIL_FIX_RESULT_HPP_20060709
#include <boost/utility/enable_if.hpp>
namespace boost { namespace coroutines { namespace detail {
template<typename Traits>
inline
void
fix_result(const typename Traits::as_tuple&,
typename
boost::enable_if_c<Traits::length == 0>::type * = 0){}
template<typename Traits>
inline
typename Traits::template at<0>::type
fix_result(const typename Traits::as_tuple& x,
typename
boost::enable_if_c<Traits::length == 1>::type * = 0){
using boost::get;
return get<0>(x);
}
template<typename Traits>
inline
typename Traits::as_tuple
fix_result(const typename Traits::as_tuple& x,
typename
boost::enable_if_c<(Traits::length > 1)>::type* =0){
return x;
}
} } }
#endif

View File

@@ -0,0 +1,140 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_FUTURE_IMPL_HPP_20060809
#define BOOST_COROUTINE_DETAIL_FUTURE_IMPL_HPP_20060809
#include <boost/optional.hpp>
#include <boost/assert.hpp>
#include <boost/optional.hpp>
#include <boost/noncopyable.hpp>
#include <boost/coroutine/detail/coroutine_accessor.hpp>
#include <boost/coroutine/detail/context_base.hpp>
namespace boost { namespace coroutines { namespace detail {
template<typename ValueType, typename ContextImpl>
class future_impl : boost::noncopyable {
public:
typedef ValueType value_type;
typedef
context_base<ContextImpl> *
context_weak_pointer;
typedef
BOOST_DEDUCED_TYPENAME
context_base<ContextImpl>::pointer
context_pointer;
typedef boost::optional<value_type> pointer;
template<typename CoroutineSelf>
future_impl(CoroutineSelf& self) :
m_coro_impl_weak(coroutine_accessor::get_impl(self)),
m_coro_impl(0),
m_waited(false)
{}
value_type&
value() {
return *m_optional;
}
value_type const&
value() const{
return *m_optional;
}
pointer&
get() {
return m_optional;
}
pointer const&
get() const{
return m_optional;
}
bool pending() {
return 0 != m_coro_impl.get();
}
template<typename T>
void assign(const T& val) {
BOOST_ASSERT(pending());
context_pointer p = m_coro_impl;
m_coro_impl = 0;
m_optional = val;
p->count_down();
if(waited() && p->signal())
p->wake_up();
}
void mark_pending() {
m_coro_impl = m_coro_impl_weak;
m_coro_impl ->count_up();
}
void mark_wait(bool how) {
m_waited = how;
}
bool waited() const {
return m_waited;
}
context_pointer context() {
BOOST_ASSERT(pending());
return m_coro_impl;
}
void wait(int n) {
m_coro_impl_weak->wait(n);
}
void wait() {
if(!pending()) return;
mark_wait(true);
try {
m_coro_impl->wait(1);
BOOST_ASSERT(!pending());
} catch (...) {
mark_wait(false);
throw;
}
mark_wait(false);
}
private:
context_weak_pointer m_coro_impl_weak;
context_pointer m_coro_impl;
bool m_waited;
boost::optional<value_type> m_optional;
};
} } }
#endif

View File

@@ -0,0 +1,84 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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)
// Copyright David Abrahams 2004. 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)
//
// Slightly modified for inclusion on coroutines/detail library.
#ifndef BOOST_COROUTINE_DETAIL_HAS_SWAP_HPP_20060709
#define BOOST_COROUTINE_DETAIL_HAS_SWAP_HPP_20060709
#include <boost/mpl/bool.hpp>
#include <boost/detail/workaround.hpp>
namespace boost { namespace coroutines {
namespace has_swap_
{
// any soaks up implicit conversions and makes the following
// operator++ less-preferred than any other such operator which
// might be found via ADL.
struct anything { template <class T> anything(T const&); };
struct no_swap
{
char (& operator,(char) )[2];
};
no_swap swap(anything,anything);
#if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable: 4675) // function found through argument dependent lookup -- duh!
#endif
template <class T>
struct has_swap_impl
{
static T& x;
BOOST_STATIC_CONSTANT(bool, value = sizeof(swap(x,x),'x') == 1);
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
typedef boost::mpl::bool_<has_swap_impl<T>::value> type;
#else
typedef boost::mpl::bool_<value> type;
#endif
};
}
template <class T>
struct has_swap
: has_swap_::has_swap_impl<T>::type
{};
#if defined(BOOST_MSVC)
# pragma warning(pop)
#endif
} }
#endif // include guard

View File

@@ -0,0 +1,42 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_INDEX_HPP_20060613
#define BOOST_COROUTINE_DETAIL_INDEX_HPP_20060613
#include <boost/preprocessor/repetition.hpp>
#include <boost/coroutine/detail/arg_max.hpp>
namespace boost { namespace coroutines { namespace detail {
/*
* Workaround for BOOST_PP_ENUM_BINARY_PARAMS, where a token
* can't be createed by appending a number to a '<'.
* NOTE: we are really abusing BOOST_PP_ENUM_BINARY_PARAMS,
* Should simply use BOOST_PP_ENUM.
*/
enum {BOOST_PP_ENUM_PARAMS(BOOST_COROUTINE_ARG_MAX, index_)};
} } }
#endif

View File

@@ -0,0 +1,62 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_IS_CALLABLE_HPP_20060601
#define BOOST_COROUTINE_DETAIL_IS_CALLABLE_HPP_20060601
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits.hpp>
#include <boost/mpl/logical.hpp>
#include <boost/mpl/has_xxx.hpp>
namespace boost { namespace coroutines { namespace detail {
template<typename T>
struct is_function_pointer :
boost::mpl::and_<
boost::is_pointer<T>,
boost::is_function<typename boost::remove_pointer<T>::type > > {
typedef is_function_pointer<T> type;
};
BOOST_MPL_HAS_XXX_TRAIT_DEF(result_type);
BOOST_MPL_HAS_XXX_TRAIT_DEF(result);
template<typename T>
struct is_functor :
boost::mpl::or_<typename has_result_type<T>::type,
typename has_result<T>::type>
{
typedef is_functor<T> type;
};
template<typename T>
struct is_callable : boost::mpl::or_<
is_functor<T>,
is_function_pointer<T> >::type {
typedef is_callable<T> type;
};
} } }
#endif

View File

@@ -0,0 +1,67 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_MAKE_TUPLE_TRAITS_HPP_20060609
#define BOOST_COROUTINE_DETAIL_MAKE_TUPLE_TRAITS_HPP_20060609
#include <boost/preprocessor/repetition.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/coroutine/detail/arg_max.hpp>
#include <boost/coroutine/tuple_traits.hpp>
namespace boost { namespace coroutines { namespace detail {
/*
* Given a mpl::vector, returns a nullary metafunction
* describing a tuple of all types in the vector.
* NOTE this is just wrong because it should work for all mpl
* sequences, not just vectors. But it is in detail, so leave it
* as is. Eventually it will be replaced by Boost.Fusion.
* @p type is a tuple of all types in TypeList.
* TypeList is one of mpl::vector0, mpl::vector1, etc.
*/
template<typename TypeList>
struct make_tuple_traits;
#define BOOST_COROUTINE_MAKE_TUPLE_TRAITS_GENERATOR(z, n, unused) \
template<BOOST_PP_ENUM_PARAMS(n, class A)> \
struct make_tuple_traits<BOOST_PP_CAT(boost::mpl::vector, n) \
<BOOST_PP_ENUM_PARAMS(n, A)> >{ \
typedef tuple_traits<BOOST_PP_ENUM_PARAMS(n, A)> type; \
}; \
/**/
/**
* Generate specializations of make_tuple
* @note This could be done more elegantly with a recursive metafunction,
* but this is simpler and works well anyway.
*/
BOOST_PP_REPEAT(BOOST_COROUTINE_ARG_MAX,
BOOST_COROUTINE_MAKE_TUPLE_TRAITS_GENERATOR, ~);
#undef BOOST_COROUTINE_MAKE_TUPLE_TRAITS_GENERATOR
} } }
#endif

View File

@@ -0,0 +1,68 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_NORETURN_HPP_20060812
#define BOOST_COROUTINE_DETAIL_NORETURN_HPP_20060812
/*
* The BOOST_COROUTINE_NORETURN macro provides a way to
* tell the compiler that a function will not return through
* the normal return path (it could return throgh a thrown exception).
* This not only provieds a possible optimization hint, but also
* prevents the compiler from complaining if a function that call
* a noreturn function does not call return itself.
*/
#include <boost/config.hpp>
#if defined(__GNUC__)
#if __GNUC_MAJOR__ > 3 || (__GNUC_MAJOR__ == 3 && __GNUC_MINOR__ > 3)
#define BOOST_COROUTINE_NORETURN(function) \
function __attribute__((__noreturn__)) \
/**/
#else // gcc 3.3
#define BOOST_COROUTINE_NORETURN(function) \
function
/**/
#endif // gcc 3.3
#elif defined (BOOST_MSVC)
#define BOOST_COROUTINE_NORETURN(function) \
__declspec(noreturn) function \
/**/
#else
//just for testing, remove the following error.
#error no default
#define BOOST_COROUTINE_NORETURN(function) \
function
/**/
#endif
#endif

View File

@@ -0,0 +1,161 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_POSIX_UTILITY_HPP_02012006
#define BOOST_COROUTINE_DETAIL_POSIX_UTILITY_HPP_02012006
#include <boost/config.hpp>
#if defined(_POSIX_VERSION)
/**
* Most of these utilities are really pure C++, but they are useful
* only on posix systems.
*/
#include <cerrno>
#include <cstddef>
#include <cstdlib>
#include <iostream>
#include <boost/type_traits.hpp>
#if defined(_POSIX_MAPPED_FILES) && _POSIX_MAPPED_FILES > 0
#include <sys/mman.h>
#endif
/**
* Stack allocation routines and trampolines for setcontext
*/
namespace boost { namespace coroutines { namespace detail { namespace posix {
#if defined(_POSIX_MAPPED_FILES) && _POSIX_MAPPED_FILES > 0
inline
void *
alloc_stack(std::size_t size) {
void * stack = ::mmap(NULL,
size,
PROT_EXEC|PROT_READ|PROT_WRITE,
#if defined(__APPLE__)
MAP_PRIVATE|MAP_ANON,
#else // ! __APPLE__
MAP_PRIVATE|MAP_ANONYMOUS,
#endif // ! __APPLE__
-1,
0
);
if(stack == MAP_FAILED) {
std::cerr <<strerror(errno)<<"\n";
abort();
}
return stack;
}
inline
void free_stack(void* stack, std::size_t size) {
::munmap(stack, size);
}
#else // non-mmap()
//this should be a fine default.
static const std::size_t stack_alignment = sizeof(void*) > 16? sizeof(void*): 16;
struct stack_aligner {
boost::type_with_alignment<stack_alignment>::type dummy;
};
/**
* Stack allocator and deleter functions.
* Better implementations are possible using
* mmap (might be required on some systems) and/or
* using a pooling allocator.
* NOTE: the SuSv3 documentation explictly allows
* the use of malloc to allocate stacks for makectx.
* We use free for guaranteed alignment.
*/
inline
void* alloc_stack(std::size_t size) {
return new stack_aligner[size/sizeof(stack_aligner)];
}
inline
void free_stack(void* stack, std::size_t size) {
delete [] static_cast<stack_aligner*>(stack);
}
#endif // non-mmap() implementation of alloc_stack()/free_stack()
/**
* The splitter is needed for 64 bit systems.
* @note The current implementation does NOT use
* (for debug reasons).
* Thus it is not 64 bit clean.
* Use it for 64 bits systems.
*/
template<typename T>
union splitter {
int int_[2];
T* ptr;
splitter(int first, int second) {
int_[0] = first;
int_[1] = second;
}
int first() {
return int_[0];
}
int second() {
return int_[1];
}
splitter(T* ptr) :ptr(ptr) {}
void operator()() {
(*ptr)();
}
};
template<typename T>
inline
void
trampoline_split(int first, int second) {
splitter<T> split(first, second);
split();
}
template<typename T>
inline
void
trampoline(T * fun) {
(*fun)();
}
}
} } }
#else
#error This header can only be included when compiling for posix systems.
#endif
#endif

View File

@@ -0,0 +1,274 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_SELF_HPP_20060809
#define BOOST_COROUTINE_DETAIL_SELF_HPP_20060809
#include <boost/noncopyable.hpp>
#include <boost/coroutine/detail/fix_result.hpp>
#include <boost/coroutine/detail/coroutine_accessor.hpp>
#include <boost/coroutine/detail/signal.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/coroutine/detail/noreturn.hpp>
namespace boost { namespace coroutines { namespace detail {
#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1400))
#define BOOST_COROUTINE_DEDUCED_TYPENAME_DEFAULT
#else
#define BOOST_COROUTINE_DEDUCED_TYPENAME_DEFAULT BOOST_DEDUCED_TYPENAME
#endif
#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1400))
#define BOOST_COROUTINE_VCPP80_WORKAROUND
#else
//for now, define this unconditionally for testing.
#define BOOST_COROUTINE_VCPP80_WORKAROUND
#endif
template<typename Coroutine>
class coroutine_self :boost::noncopyable {
public:
typedef Coroutine coroutine_type;
typedef coroutine_self<coroutine_type> type;
friend struct detail::coroutine_accessor;
typedef BOOST_DEDUCED_TYPENAME coroutine_type
::impl_type impl_type;
// Note, no reference counting here.
typedef impl_type * impl_ptr;
typedef BOOST_DEDUCED_TYPENAME coroutine_type
::result_type result_type;
typedef BOOST_DEDUCED_TYPENAME coroutine_type
::result_slot_type result_slot_type;
typedef BOOST_DEDUCED_TYPENAME coroutine_type
::yield_result_type yield_result_type;
typedef BOOST_DEDUCED_TYPENAME coroutine_type
::result_slot_traits result_slot_traits;
typedef BOOST_DEDUCED_TYPENAME coroutine_type
::arg_slot_type arg_slot_type;
typedef BOOST_DEDUCED_TYPENAME coroutine_type
::arg_slot_traits arg_slot_traits;
typedef BOOST_DEDUCED_TYPENAME coroutine_type
::yield_traits yield_traits;
#ifndef BOOST_COROUTINE_VCPP80_WORKAROUND
# define BOOST_COROUTINE_param_with_default(z, n, type_prefix) \
BOOST_DEDUCED_TYPENAME call_traits \
<BOOST_PP_CAT(BOOST_PP_CAT(type_prefix, n), _type)>::param_type \
BOOST_PP_CAT(arg, n) = \
BOOST_PP_CAT(BOOST_PP_CAT(type_prefix, n), _type)() \
/**/
yield_result_type yield
(BOOST_PP_ENUM
(BOOST_COROUTINE_ARG_MAX,
BOOST_COROUTINE_param_with_default,
BOOST_DEDUCED_TYPENAME yield_traits::arg))
{
return yield_impl
(BOOST_DEDUCED_TYPENAME
coroutine_type::result_slot_type
(BOOST_PP_ENUM_PARAMS
(BOOST_COROUTINE_ARG_MAX,
arg)));
}
template<typename Target>
yield_result_type yield_to
(Target& target
BOOST_PP_ENUM_TRAILING
(BOOST_COROUTINE_ARG_MAX,
BOOST_COROUTINE_param_with_default,
typename Target::arg))
{
typedef BOOST_DEDUCED_TYPENAME Target::arg_slot_type slot_type;
return yield_to_impl
(target, slot_type(BOOST_PP_ENUM_PARAMS
(BOOST_COROUTINE_ARG_MAX,
arg)));
}
#else
/*
* VC8.0 can't handle the call_traits meta-invocation inside
* a function parameter list (except when it does, see operator()).
* Splitting it in separate typedefs
* fixes the problem.
*/
#define BOOST_COROUTINE_param_typedef(z, n, prefix_tuple) \
typedef BOOST_DEDUCED_TYPENAME \
call_traits< \
BOOST_PP_CAT \
(BOOST_PP_CAT \
(BOOST_PP_TUPLE_ELEM(2, 0, prefix_tuple), n), \
_type) \
>::param_type \
BOOST_PP_CAT \
(BOOST_PP_CAT \
(BOOST_PP_TUPLE_ELEM(2, 1, prefix_tuple), n), \
_type) \
/**/;
/*
* Generate lines like this:
* 'typedef typename call_traits<typename coroutine_type::yield_traits::argN_type>::param_type yield_call_argN_type;'
*/
BOOST_PP_REPEAT(BOOST_COROUTINE_ARG_MAX,
BOOST_COROUTINE_param_typedef,
(BOOST_DEDUCED_TYPENAME
coroutine_type::yield_traits::arg, yield_call_arg));
/*
* Generate lines like this:
* 'typedef typename call_traits<typename coroutine_type::argN_type>::param_type call_argN_type;'
*/
BOOST_PP_REPEAT(BOOST_COROUTINE_ARG_MAX,
BOOST_COROUTINE_param_typedef,
(BOOST_DEDUCED_TYPENAME
coroutine_type::arg, call_arg));
#undef BOOST_COROUTINE_param_typedef
#undef BOOST_COROUTINE_param_with_default
#define BOOST_COROUTINE_param_with_default(z, n, prefix_tuple) \
BOOST_PP_CAT(BOOST_PP_CAT \
(BOOST_PP_TUPLE_ELEM(2, 0, prefix_tuple), \
n), _type) \
BOOST_PP_CAT(arg, n) = \
BOOST_PP_CAT(BOOST_PP_CAT \
(BOOST_PP_TUPLE_ELEM(2, 1, prefix_tuple), \
n), _type)() \
/**/
yield_result_type yield
(BOOST_PP_ENUM(BOOST_COROUTINE_ARG_MAX,
BOOST_COROUTINE_param_with_default,
(yield_call_arg ,
BOOST_COROUTINE_DEDUCED_TYPENAME_DEFAULT
coroutine_type::yield_traits::arg)))
{
return yield_impl
(result_slot_type
(BOOST_PP_ENUM_PARAMS(BOOST_COROUTINE_ARG_MAX,arg)));
}
template<typename Target>
yield_result_type yield_to
(Target& target
BOOST_PP_ENUM_TRAILING
(BOOST_COROUTINE_ARG_MAX,
BOOST_COROUTINE_param_with_default,
(BOOST_DEDUCED_TYPENAME Target::self::call_arg,
BOOST_COROUTINE_DEDUCED_TYPENAME_DEFAULT Target::arg)))
{
typedef typename Target::arg_slot_type type;
return yield_to_impl
(target, type
(BOOST_PP_ENUM_PARAMS
(BOOST_COROUTINE_ARG_MAX, arg)));
}
#endif
#undef BOOST_COROUTINE_param_with_default
BOOST_COROUTINE_NORETURN(void exit()) {
m_pimpl -> exit_self();
abort();
}
yield_result_type result() {
return detail::fix_result<
BOOST_DEDUCED_TYPENAME
coroutine_type::arg_slot_traits>(*m_pimpl->args());
}
bool pending() const {
BOOST_ASSERT(m_pimpl);
return m_pimpl->pending();
}
/// @c true only if this @c self object was created by the passed @a coroutine
template <typename SomeCoroutine>
bool is_from(const SomeCoroutine& coroutine) const
{
// get_impl() only accepts non-const ref... a mistake, IMO.
return static_cast<void*>(coroutine_accessor::get_impl(const_cast<SomeCoroutine&>(coroutine)).get()) ==
static_cast<void*>(m_pimpl);
}
/// opaque token used to correlate this 'self' with its corresponding coroutine
void* get_id() const { return m_pimpl; }
private:
coroutine_self(impl_type * pimpl, detail::init_from_impl_tag) :
m_pimpl(pimpl) {}
yield_result_type yield_impl(BOOST_DEDUCED_TYPENAME
coroutine_type::result_slot_type result) {
typedef BOOST_DEDUCED_TYPENAME
coroutine_type::result_slot_type slot_type;
BOOST_ASSERT(m_pimpl);
this->m_pimpl->bind_result(&result);
this->m_pimpl->yield();
return detail::fix_result<
BOOST_DEDUCED_TYPENAME
coroutine_type::arg_slot_traits>(*m_pimpl->args());
}
template<typename TargetCoroutine>
yield_result_type yield_to_impl(TargetCoroutine& target,
BOOST_DEDUCED_TYPENAME TargetCoroutine
::arg_slot_type args) {
BOOST_ASSERT(m_pimpl);
coroutine_accessor::get_impl(target)->bind_args(&args);
coroutine_accessor::get_impl(target)->bind_result_pointer(m_pimpl->result_pointer());
this->m_pimpl->yield_to(*coroutine_accessor::get_impl(target));
return detail::fix_result<
BOOST_DEDUCED_TYPENAME
coroutine_type::arg_slot_traits>(*m_pimpl->args());
}
impl_ptr get_impl() {
return m_pimpl;
}
impl_ptr m_pimpl;
};
} } }
#endif

View File

@@ -0,0 +1,67 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_SIGNAL_HPP_20060728
#define BOOST_COROUTINE_DETAIL_SIGNAL_HPP_20060728
#include <boost/coroutine/detail/future_impl.hpp>
namespace boost { namespace coroutines { namespace detail {
/*
* Private interface for coroutine signaling/waiting.
* These class is friend of future_impl and
* its static members are invoked by asynchronous callback functions.
*/
struct wait_gateway {
template<typename Future>
static void wait(Future& f, int n) {
f.wait(n);
}
template<typename Future>
static
bool waited(const Future& f) {
return f.waited();
}
template<typename Future>
static
void mark_wait(Future& f, bool how) {
f.mark_wait(how);
}
template<typename Future>
static
BOOST_DEDUCED_TYPENAME
Future::impl_pointer
get_impl(Future& f) {
return f.m_ptr;
}
};
} } }
#endif

View File

@@ -0,0 +1,56 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_SIGNATURE_HPP_20060609
#define BOOST_COROUTINE_DETAIL_SIGNATURE_HPP_20060609
#include <boost/preprocessor/repetition.hpp>
#include <boost/coroutine/detail/arg_max.hpp>
namespace boost{ namespace coroutines{ namespace detail{
/*
* Derived from an mpl::vector describing
* 'Function' arguments types.
*/
template<typename Function>
struct signature;
/*
* Generate specializations for the signature trait class.
*/
#define BOOST_COROUTINE_SIGNATURE_GENERATOR(z, n, unused) \
template <class R BOOST_PP_ENUM_TRAILING_PARAMS(n, class A)> \
struct signature<R( BOOST_PP_ENUM_PARAMS(n,A) ) > \
: boost::mpl::BOOST_PP_CAT(vector,n)< \
BOOST_PP_ENUM_PARAMS(n,A) \
> {}; \
/**/
BOOST_PP_REPEAT(BOOST_COROUTINE_ARG_MAX, BOOST_COROUTINE_SIGNATURE_GENERATOR, ~);
#undef BOOST_COROUTINE_SIGNATURE_GENERATOR
} } }
#endif

View File

@@ -0,0 +1,38 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_SWAP_CONTEXT_HPP_20060611
#define BOOST_COROUTINE_SWAP_CONTEXT_HPP_20060611
namespace boost{ namespace coroutines { namespace detail {
class default_hint {};
class yield_hint: public default_hint {};
class yield_to_hint: public default_hint {};
class invoke_hint: public default_hint {};
} } }
#endif

View File

@@ -0,0 +1,102 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_WAIT_IMPL_HPP_20060728
#define BOOST_COROUTINE_DETAIL_WAIT_IMPL_HPP_20060728
#include <boost/tuple/tuple.hpp>
#include <boost/coroutine/detail/signal.hpp>
namespace boost { namespace coroutines { namespace detail {
/*
* Inokes mark_wait('how') on the 'Idx'th element of 't'
* then calls marker::wait<Idx-1> with the same arguments.
* returns the result of marker::wait<Idx-1>(...) plus 1 if
* the 'Idx'th.pending() is true or plus 0 otherwise.
*
*/
template<int Idx>
struct marker {
template<typename Tuple>
static int mark(Tuple& t, bool how) {
wait_gateway::mark_wait(t.template get<Idx-1>(), how);
return marker<Idx -1>::mark(t, how) + (t.template get<Idx-1>().pending()? 1:0);
}
};
/* Recursion terminator */
template<>
struct marker<0> {
template<typename Tuple>
static int mark(Tuple&, bool) { return 0;}
};
template<typename Tuple>
void wait_n(const Tuple& t, int n) {
BOOST_STATIC_ASSERT(boost::tuples::length<Tuple>::value);
wait_gateway::wait(t.get<0>(), n);
}
/*
* Wait for at least one future in 'wt' tuple to be signaled.
* If at least one future has been already signaled do not
* block but returns immediatley (prevents deadlocks).
*/
template<typename Tuple>
void wait_impl(Tuple wt) {
try {
if(marker<boost::tuples::length<Tuple>::value>::mark(wt, true) > 0)
wait_n(wt, 1);
} catch (...) {
marker<boost::tuples::length<Tuple>::value>::mark(wt, false);
throw;
}
int res = marker<boost::tuples::length<Tuple>::value>::mark(wt, false);
BOOST_ASSERT(res < boost::tuples::length<Tuple>::value);
(void)res;
}
/*
* Wait for all futures in 'wt' tuple to be signaled.
*/
template<typename Tuple>
void wait_all_impl(Tuple wt) {
int res = marker<boost::tuples::length<Tuple>::value>::mark(wt, true);
try {
wait_n(wt, res);
} catch (...) {
marker<boost::tuples::length<Tuple>::value>::mark(wt, false);
throw;
}
res = marker<boost::tuples::length<Tuple>::value>::mark(wt, false);
BOOST_ASSERT(res == 0);
}
} } }
#endif

View File

@@ -0,0 +1,54 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_YIELD_RESULT_TYPE_HPP_20060609
#define BOOST_COROUTINE_DETAIL_YIELD_RESULT_TYPE_HPP_20060609
#include <boost/coroutine/detail/make_tuple_traits.hpp>
#include <boost/mpl/vector.hpp>
namespace boost{ namespace coroutines { namespace detail {
/**
* Same as make_tuple_traits, but if
* @p TypeList is singular, @p type is the single element, and
* if TypeList is empty, @p type is @p void.
*/
template<typename TypeList>
struct yield_result_type {
typedef typename make_tuple_traits<TypeList>::type type;
};
template<typename T>
struct yield_result_type <boost::mpl::vector1<T> >{
typedef T type;
};
template<>
struct yield_result_type <boost::mpl::vector0<> >{
typedef void type;
};
} } }
#endif

View File

@@ -0,0 +1,80 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_EXCEPTION_HPP_20060601
#define BOOST_COROUTINE_EXCEPTION_HPP_20060601
#include <exception>
#include <typeinfo>
namespace boost { namespace coroutines {
// All coroutine exceptions are derived from this base.
class exception_base : public std::exception {};
// This exception is thrown when a coroutine is requested
// to exit.
class exit_exception: public exception_base {};
// This exception is thrown on a coroutine invocation
// if a coroutine exits without
// returning a result. Note that calling invoke()
// on an already exited coroutine is undefined behaviour.
class coroutine_exited: public exception_base {};
// This exception is thrown on a coroutine invocation
// if a coroutine enter the wait state without
// returning a result. Note that calling invoke()
// on a waiting coroutine is undefined behaviour.
class waiting : public exception_base {};
class unknown_exception_tag {};
// This exception is thrown on a coroutine invocation
// if the coroutine is exited by an uncatched exception
// (not derived from exit_exception). abnormal_exit::type()
// returns the typeid of that exception if it is derived
// from std::exception, else returns typeid(unknonw_exception_tag)
class abnormal_exit : public std::exception {
public:
abnormal_exit(std::type_info const& e) :
m_e (e) {};
const char* what() const throw() {
return m_e == typeid(unknown_exception_tag)?
"unknown exception" :
m_e.name();
}
std::type_info const& type() const throw() {
return m_e;
}
private:
std::type_info const& m_e;
};
} }
#endif

View File

@@ -0,0 +1,305 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_FUTURE_HPP_20060728
#define BOOST_COROUTINE_FUTURE_HPP_20060728
// Max number of futures that can be waited for.
#ifndef BOOST_COROUTINE_WAIT_MAX
#define BOOST_COROUTINE_WAIT_MAX 10
#endif
// On Linux systems, use native swapcontext() et al. rather than
// Boost.Coroutine homebrew assembler
#define BOOST_COROUTINE_NO_ASM
// default_context_impl.hpp must be first for weird Apple bug
#include <boost/coroutine/detail/default_context_impl.hpp>
#include <boost/none.hpp>
#include <boost/config.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/preprocessor/repetition.hpp>
#include <boost/preprocessor/facilities/intercept.hpp>
#include <boost/coroutine/move.hpp>
#include <boost/coroutine/tuple_traits.hpp>
#include <boost/coroutine/detail/signal.hpp>
#include <boost/coroutine/detail/arg_max.hpp>
#include <boost/coroutine/detail/call_impl.hpp>
#include <boost/coroutine/detail/wait_impl.hpp>
#include <boost/coroutine/detail/future_impl.hpp>
namespace boost { namespace coroutines {
template<
BOOST_PP_ENUM_BINARY_PARAMS
(BOOST_COROUTINE_ARG_MAX,
typename T,
= boost::tuples::null_type BOOST_PP_INTERCEPT),
typename ContextImpl = detail::default_context_impl
>
class future :
public movable
<future<BOOST_PP_ENUM_PARAMS(BOOST_COROUTINE_ARG_MAX, T)> >
{
friend struct detail::wait_gateway;
typedef void (future::*safe_bool)();
void safe_bool_true() {}
public:
typedef ContextImpl context_impl;
typedef tuple_traits<
BOOST_PP_ENUM_PARAMS
(BOOST_COROUTINE_ARG_MAX, T)
> tuple_traits_type;
typedef boost::mpl::bool_<tuple_traits_type::length == 1>
is_singular;
typedef BOOST_DEDUCED_TYPENAME tuple_traits_type::as_tuple tuple_type;
typedef BOOST_DEDUCED_TYPENAME boost::mpl::eval_if<
boost::mpl::not_<is_singular>,
boost::mpl::identity<tuple_type>,
BOOST_DEDUCED_TYPENAME tuple_traits_type::template at<0>
>::type value_type;
typedef detail::future_impl<tuple_type, context_impl> future_impl;
typedef future_impl * impl_pointer;
template<typename CoroutineSelf>
future(CoroutineSelf& self) :
m_ptr(new future_impl(self)) {}
future(move_from<future> rhs) :
m_ptr(rhs->pilfer()) {}
value_type& operator *() {
BOOST_ASSERT(m_ptr);
wait();
return remove_tuple(m_ptr->value(), boost::mpl::not_<is_singular>());
}
const value_type& operator *() const{
BOOST_ASSERT(m_ptr);
BOOST_ASSERT(m_ptr->get());
wait();
return remove_tuple(m_ptr->value(), boost::mpl::not_<is_singular>());
}
future& operator=(move_from<future> rhs) {
future(rhs).swap(*this);
return *this;
}
future& operator=(const value_type& rhs) {
BOOST_ASSERT(!pending());
m_ptr->get() = tuple_type(rhs);
return *this;
}
future& operator=(none_t) {
BOOST_ASSERT(!pending());
m_ptr->get() = none;
return *this;
}
operator safe_bool() const {
BOOST_ASSERT(m_ptr);
return m_ptr->get()?
&future::safe_bool_true: 0;
}
BOOST_DEDUCED_TYPENAME
future_impl::pointer &
operator ->() {
BOOST_ASSERT(m_ptr);
wait();
return m_ptr->get();
}
BOOST_DEDUCED_TYPENAME
future_impl::pointer const
operator ->() const {
BOOST_ASSERT(m_ptr);
wait();
return m_ptr->get();
}
friend void swap(future& lhs, future& rhs) {
std::swap(lhs.m_ptr, rhs.m_ptr);
}
// On destruction, if the future is
// pending it will be destroyed.
~future() {
if(m_ptr) {
wait();
delete m_ptr;
}
}
// Return true if an async call has
// been scheduled for this future.
bool pending() const {
BOOST_ASSERT(m_ptr);
return m_ptr->pending();
}
private:
void wait(int n) {
m_ptr->wait(n);
}
void wait() {
m_ptr->wait();
}
template<typename T>
value_type& remove_tuple(T& x, boost::mpl::false_) {
return boost::get<0>(x);
}
template<typename T>
value_type& remove_tuple(T& x, boost::mpl::true_) {
return x;
}
void mark_wait(bool how) {
BOOST_ASSERT(m_ptr);
m_ptr->mark_wait(how);
}
bool waited() const {
BOOST_ASSERT(m_ptr);
return m_ptr->waited();
}
impl_pointer pilfer() {
impl_pointer ptr = m_ptr;
m_ptr = 0;
return ptr;
}
impl_pointer m_ptr;
};
#define BOOST_COROUTINE_gen_call_overload(z, n, unused) \
template< \
BOOST_PP_ENUM_PARAMS(n, typename T) \
BOOST_PP_COMMA_IF(n) \
typename Functor, \
typename Coroutine> \
future<BOOST_PP_ENUM_PARAMS(n, T)> \
call(const Functor f, const Coroutine& coro) { \
return detail::call_impl<future<BOOST_PP_ENUM_PARAMS (n,T)> >(f, coro); \
} \
/**/
/*
* Generate overloads of call<...>(function, coroutine) for
* an arbitrary argument numbers that will forward to
* detail::call_impl<future<...> >(function, coroutine)
*/
BOOST_PP_REPEAT(BOOST_COROUTINE_ARG_MAX,
BOOST_COROUTINE_gen_call_overload,
~);
#define BOOST_COROUTINE_empty(z, n, name) \
/**/
#define BOOST_COROUTINE_gen_reference(z, n, unused) \
BOOST_PP_CAT(T, n) & \
/**/
#define BOOST_COROUTINE_gen_wait_non_zero(z, n, name)\
template<BOOST_PP_ENUM_PARAMS(n, typename T)> \
void name (BOOST_PP_ENUM_BINARY_PARAMS(n, T, &arg)) { \
detail::BOOST_PP_CAT(name, _impl) \
(boost::tuple<BOOST_PP_ENUM(n, BOOST_COROUTINE_gen_reference, ~)> \
(BOOST_PP_ENUM_PARAMS(n, arg))); \
} \
/**/
#define BOOST_COROUTINE_gen_wait(z, n, name) \
BOOST_PP_IF(n, \
BOOST_COROUTINE_gen_wait_non_zero, \
BOOST_COROUTINE_empty)(z, n, name) \
/**/
/*
* Generate overloads of wait(coro, ...) for
* an arbitrary argument number that will
* forward to detail::wait_impl(coro, tuple<...>)
*/
BOOST_PP_REPEAT(BOOST_COROUTINE_WAIT_MAX,
BOOST_COROUTINE_gen_wait,
wait);
/*
* Generate wait_all(coro, ...) for an arbitrary arguement
* number that will forward to
* detail::wait_all_impl(coro, tuple<...>)
*/
BOOST_PP_REPEAT(BOOST_COROUTINE_WAIT_MAX,
BOOST_COROUTINE_gen_wait,
wait_all);
#undef BOOST_COROUTINE_gen_wait
#undef BOOST_COROUTINE_empty
#undef BOOST_COROUTINE_gen_reference
#undef BOOST_COROUTINE_gen_wait_non_zero
#undef BOOST_COROUTINE_gen_call_overload
template<typename Future >
struct make_callback_result {
typedef detail::callback<Future> type;
};
/*
* Returns a callback object that when invoked
* will signal the associated coroutine::self object.
* It will extend the lifetime of the object until
* it is signaled. More than one callback object
* can be pending at any time. The coroutine self
* will last at least untill the last pending callback
* is fired.
*/
template<typename Future>
BOOST_DEDUCED_TYPENAME
make_callback_result<Future>
::type
make_callback(Future& future) {
return BOOST_DEDUCED_TYPENAME make_callback_result<Future>::type
(future);
}
} }
#endif

View File

@@ -0,0 +1,155 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_GENERATOR_HPP_20060812
#define BOOST_COROUTINE_GENERATOR_HPP_20060812
#include <iterator>
#include <boost/optional.hpp>
#include <boost/none.hpp>
#include <boost/coroutine/shared_coroutine.hpp>
namespace boost { namespace coroutines {
namespace detail {
template<typename T>
class tag {};
class empty {};
template<typename Category, typename ValueType>
struct make_std_iterator {
typedef std::iterator<Category,
ValueType,
std::ptrdiff_t,
BOOST_DEDUCED_TYPENAME boost::remove_reference<ValueType>::type *, //pointer
BOOST_DEDUCED_TYPENAME boost::remove_reference<ValueType>::type & //reference
> type;
};
}
// This simple class implement generators (a simple
// subset of coroutines) in the form of an InputIterator
// interface. It also models to the AdaptableGenerator concept.
// Finally it is ConvertibleToBool.
template<typename ValueType,
typename Coroutine =
shared_coroutine<ValueType()> >
class generator : public boost::mpl::eval_if<boost::is_same<ValueType, void>,
boost::mpl::identity<detail::empty>,
detail::make_std_iterator<
std::input_iterator_tag,
typename Coroutine::result_type> >::type {
typedef void(generator::*safe_bool)();
typedef ValueType internal_value_type;
public:
typedef Coroutine coroutine_type;
typedef BOOST_DEDUCED_TYPENAME
coroutine_type::result_type result_type;
typedef result_type value_type;
typedef BOOST_DEDUCED_TYPENAME coroutine_type::self self;
generator() {}
template<typename Functor>
generator(Functor f) :
m_coro(f),
m_val(assign(detail::tag<result_type>())){};
generator(const generator& rhs) :
m_coro(rhs.m_coro),
m_val(rhs.m_val) {}
value_type operator*() {
return *m_val;
}
generator& operator++() {
m_val = assign(detail::tag<result_type>());
return *this;
}
generator operator++(int) {
generator t(*this);
++(*this);
return t;
}
friend
bool operator==(const generator& lhs, const generator& rhs) {
return lhs.m_val == rhs.m_val;
}
friend
bool operator != (const generator& lhs, const generator & rhs) {
return !(lhs == rhs);
}
operator safe_bool () const {
return m_val? &generator::safe_bool_true: 0;
}
value_type operator()() {
return *(*this)++;
}
private:
void safe_bool_true () {};
// hack to handle correctly void result types.
struct optional_void {
optional_void() : m_result(true) {}
optional_void(boost::none_t) : m_result(false) {}
void operator*() const {}
operator bool() const { return m_result; };
bool m_result;
};
typedef BOOST_DEDUCED_TYPENAME
boost::mpl::if_<boost::is_same<value_type, void>,
optional_void,
boost::optional<value_type> >::type optional_type;
template<typename T>
optional_type assign(detail::tag<T>) {
return m_coro? m_coro(std::nothrow): boost::none;
}
optional_type assign(detail::tag<void>) {
return m_coro? (m_coro(std::nothrow), optional_type()): boost::none;
}
// There is a possible EBO here. May be use compressed pair.
coroutine_type m_coro;
optional_type m_val;
};
} }
#endif

View File

@@ -0,0 +1,322 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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)
// (C) Copyright David Abrahams 2004-2005.
// 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)
//
// move.hpp, modified for inclusion in coroutines/detail.
// It support movable only types (i.e. explicit move or move
// from rvalue).
//
// This file should be removed (and coroutine updated)
// when/if the original move.hpp is included in boost
//
// Note some move support for older compilers is left inplace even if
// Boost.Coroutine is not really supported on them.
//
#ifndef BOOST_COROUTINE_MOVE_HPP_20060703
#define BOOST_COROUTINE_MOVE_HPP_20060703
#include <boost/type_traits/is_convertible.hpp>
#include <boost/mpl/if.hpp>
#include <boost/preprocessor/seq/seq.hpp>
#include <boost/preprocessor/seq/elem.hpp>
#include <boost/preprocessor/identity.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/coroutine/detail/has_swap.hpp>
#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
#include <boost/ref.hpp>
#include <boost/type_traits/is_class.hpp>
// MSVC 6/7 decides the implicit move assignment operator is ambiguous.
# define BOOST_COROUTINE_MOVE_COPY_SWAP_ASSIGN // Also binds rvalues to non-const refs in assignment
#endif
// Normal EDG like Comeau does enough (N)RVO that the only case where
// turning on the move construction hacks help is when *explicitly*
// direct-initializing an object. These cases are important, but the
// hacks break down in strict mode.
// Borland will always copy a temporary when used in a direct
// initialization. Enabling the move construction hacks just makes
// the compiler ICE, so we'll skip 'em
// Intel 8.x on win32 needs help on direct initialization because it
// won't automatically elide copies. Earlier versions don't seem to
// respond to the move construction hacks, because they blithely bind
// rvalues to non-const references.
#if defined(BOOST_INTEL_CXX_VERSION)
# if !defined(_MSC_VER) /* Intel-Linux */ \
|| BOOST_INTEL_CXX_VERSION >= 800
# define BOOST_COROUTINE_IMPLICIT_MOVE_CTOR_FOR_COPYABLE_TYPES
# else
// because of the way rvalues bind to non-const references, move
// assignment is never called implicitly. This at least avoids a copy
// when the source is a genuine rvalue.
# define BOOST_COROUTINE_MOVE_COPY_SWAP_ASSIGN
# endif
#endif
namespace boost { namespace coroutines {
// This is the class that enables the distinction of const lvalues in
// the move overload set in case you don't like using the templated
// reference method. Movable types T used with const_lvalue overloads
// must have a separate conversion to const_lvalue<T>
template <class X>
struct const_lvalue
{
explicit const_lvalue(X const* p)
: p(p) {}
// It acts like a smart pointer, for syntactic convenience
X const& operator*() const { return *p; }
X const* operator->() const { return p; }
#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
// A convenience for constructors taking a const_lvalue. As a
// result, implicit_cast<X const&>(rhs) can be used to get at the
// rhs uniformly.
operator X const&() const { return **this; }
#endif
friend inline X const& copy_source(const_lvalue<X> x) { return *x; }
#ifdef BOOST_COROUTINE_DEBUG_MOVE
~const_lvalue()
{
p =0;
}
#endif
protected:
X const* p; // this pointer will refer to the object from which to move
};
template <class T>
inline T const& copy_source(T& x) { return x; }
template <class X>
struct move_from : const_lvalue<X>
{
explicit move_from(X* p)
: const_lvalue<X>(p) {}
// Some compilers need this; seems to do no harm in general.
explicit move_from(X& x)
: const_lvalue<X>(&x) {}
#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
// It would be perverse if we inherited const_lvalue's conversion
// to X const& without providing this one.
operator X&() const { return **this; }
#endif
// It acts like a smart pointer, for syntactic convenience
X& operator*() const { return *const_cast<X*>(this->p); }
X* operator->() const { return const_cast<X*>(this->p); }
};
// Detect whether T is movable
template <class T>
struct is_movable
: boost::is_convertible<T,move_from<T> >
{
};
#if defined(BOOST_COROUTINE_MOVE_COPY_SWAP_ASSIGN) || defined(__BORLANDC__)
namespace move_
{
# if BOOST_WORKAROUND(BOOST_MSVC, == 1300)
template <class T>
struct move_result
: mpl::if_<
is_class<T>,
typename mpl::if_<
is_movable<T>
, move_from<T>
, reference_wrapper<T>
>::type
, T&
>
{};
# else // default version
template <class T>
struct move_result
: mpl::if_< is_movable<T>, move_from<T> , T& >
{};
# endif
}
template <class T>
typename move_::move_result<T>::type
move(T& x)
{
typedef typename move_::move_result<T>::type r;
return r(x);
}
#else
template <class T>
inline
typename boost::mpl::if_<
is_movable<T>
, T
, T&
>::type
move(T& x)
{
typedef typename boost::mpl::if_<
is_movable<T>
, move_from<T>
, T&
>::type r1;
typedef typename boost::mpl::if_<
is_movable<T>
, T
, T&
>::type r2;
return r2(r1(x));
}
#endif
// CRTP base class for conveniently making movable types. You don't
// have to use this to make a type movable (if, for example, you don't
// want the MI non-EBO penalty); you just need to provide the
// conversion to move_from<Derived> yourself in that case.
template <class Derived>
struct movable
{
operator move_from<Derived>()
{
return move_from<Derived>(static_cast<Derived*>(this));
}
operator const_lvalue<Derived>() const
{
return const_lvalue<Derived>(static_cast<Derived const*>(this));
}
protected:
movable() {}
private:
// any class that wants to be movable should to define its copy
// ctor and assignment using the macros below, or else those
// should remain private.
movable(movable&);
movable& operator=(movable&);
};
namespace move_
{
// Algorithms lifted directly from
// http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1377.htm
template <class T>
void
swap(T& a, T& b)
{
T tmp(boost::coroutines::move(a));
a = boost::coroutines::move(b);
b = boost::coroutines::move(tmp);
}
}
using move_::swap;
// This is for GCC2 compatibility. GCC2's standard lib puts std::swap
// into the global namespace, causing ambiguities with boost::swap
// when brought in with a using declaration.
namespace move_swap_
{
template <class T>
void
move_swap(T& a, T& b, mpl::true_)
{
swap(a,b); // use ADL
}
template <class T>
void
move_swap(T& a, T& b, mpl::false_)
{
move_::swap(a,b);
}
template <class T>
void
move_swap(T& a, T& b)
{
typedef typename has_swap<T>::type has_swap_;
move_swap(a,b, has_swap_());
}
}
using move_swap_::move_swap;
// I wonder whether it's a good idea to have the 1-argument and
// 3-argument overloads that do different things?
template <class InputIterator, class OutputIterator>
OutputIterator
move(InputIterator first, InputIterator last, OutputIterator result)
{
for (; first != last; ++first, ++result)
*result = move(*first, 0);
return result;
}
template <class BidirectionalIterator1, class BidirectionalIterator2>
BidirectionalIterator2
move_backward(BidirectionalIterator1 first, BidirectionalIterator1 last,
BidirectionalIterator2 result)
{
while (last != first)
*--result = move(*--last, 0);
return result;
}
} }
#endif

View File

@@ -0,0 +1,72 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_SHARED_COROUTINE_HPP_20060812
#define BOOST_COROUTINE_SHARED_COROUTINE_HPP_20060812
#include <boost/coroutine/coroutine.hpp>
namespace boost { namespace coroutines {
// This class is a workaround for the widespread lack of move
// semantics support. It is a refrence counted wrapper around
// the coroutine object.
// FIXME: ATM a shared_coroutine is-a coroutine. This is to avoid
// inheriting privately and cluttering the code with lots of using
// declarations to unhide coroutine members and nested types.
// From a purity point of view, coroutines and shared_coroutines should
// be two different types.
template<typename Signature, typename ContextImpl = detail::default_context_impl>
class shared_coroutine : public coroutine<Signature, ContextImpl> {
public:
typedef coroutine<Signature, ContextImpl> coroutine_type;
shared_coroutine() {}
template<typename Functor>
shared_coroutine(Functor f,
std::ptrdiff_t stack_size =
detail::default_stack_size) :
coroutine_type(f, stack_size) {}
shared_coroutine(move_from<coroutine_type> src):
coroutine_type(src) {}
shared_coroutine(const shared_coroutine& rhs) :
coroutine_type(rhs.m_pimpl.get(), detail::init_from_impl_tag()) {}
shared_coroutine& operator=(move_from<coroutine_type> src) {
shared_coroutine(src).swap(*this);
return *this;
}
shared_coroutine& operator=(const shared_coroutine& rhs) {
shared_coroutine(rhs).swap(*this);
return *this;
}
private:
};
} }
#endif

View File

@@ -0,0 +1,170 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_TUPLE_TRAITS_HPP_20060613
#define BOOST_COROUTINE_TUPLE_TRAITS_HPP_20060613
#include <boost/tuple/tuple.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/facilities/intercept.hpp>
#include <boost/type_traits.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/coroutine/detail/arg_max.hpp>
namespace boost { namespace coroutines {
namespace detail {
/*
* NOTE & FIXME: coroutine_traits relies on the fact that we can construct a
* boost::tuple specifing more arguments of type null_type than
* required without generating an error. This is an undocumented
* 'feature' and doesn't actually work for nullary tuples,
* so we need to detect this case and handle it with tuple_workaround.
* If ever boost::tuple is changed (for example by switching to fusion)
* tuple_workaround should be used in all cases to handle extra
* parameters.
* The real solution would be to have an internal tuple
* type that derives from boost::tuple and handles all cases we care about.
* Or better, just use Boost.Fusion.
* In general the code in this file needs to be put in a better shape,
* eliminating all corner cases.
*/
/*
* A boost::tuple<> is not constructible from an arbitrary
* number of null_types (while non nullary tuples are).
* This class takes care of this assimmetry.
*/
struct tuple_workaround : boost::tuple<> {
# define BOOST_COROUTINE_arg_null_typecr(z, n, unused)\
const boost::tuples::null_type& \
/**/
tuple_workaround
(BOOST_PP_ENUM
(BOOST_COROUTINE_ARG_MAX,
BOOST_COROUTINE_arg_null_typecr,
~)){}
tuple_workaround(const tuple_workaround&) {}
tuple_workaround() {}
# undef BOOST_COROUTINE_arg_null_typecr
};
} /* detail */
// All tuple traits must be derived from this
// class to be correctly recognized.
struct tuple_traits_tag {};
template<typename T>
struct get_length {
enum { length = T::length };
};
template<typename T>
struct is_nullary : boost::mpl::bool_<boost::tuples::length<T>::value == 0> { };
template<typename T>
struct is_singular : boost::mpl::bool_<boost::tuples::length<T>::value == 1> { };
// Given a tuple_traits, makes a tuple of it
// Simply returns the internal tuple type, unless
// the tuple is nullary, then apply the nullary tuple workaround
template<typename T>
struct make_as_tuple :
boost::mpl::if_<
is_nullary<T>,
detail::tuple_workaround,
T
> {};
// Used to implement the next metafunction,
// Splitted in two parts to satisfy the compiler.
template<typename T>
struct step_2 :
boost::mpl::eval_if<
is_singular<T>,
boost::tuples::element<0, typename make_as_tuple<T>::type >,
boost::mpl::identity<typename make_as_tuple<T>::type> > { };
// Given a trait class return the internal tuple type modified
// as a return value.
// The algorithm is as follow:
// - If the tuple is nullary returns 'void'.
// - If it singular returns the first type
// - Else return the tuple itself.
template<typename T>
struct make_result_type :
boost::mpl::eval_if<
is_nullary<T>,
boost::mpl::identity<void>,
step_2<T> > { };
template<
BOOST_PP_ENUM_BINARY_PARAMS
(BOOST_COROUTINE_ARG_MAX,
typename T,
= boost::tuples::null_type BOOST_PP_INTERCEPT)>
struct tuple_traits : tuple_traits_tag {
public:
// This is the straightforward boost::tuple trait
// derived from the argument list. It is not
// directly used in all cases.
typedef boost::tuple
<BOOST_PP_ENUM_PARAMS
(BOOST_COROUTINE_ARG_MAX, T)> internal_tuple_type;
// FIXME: Currently coroutine code does not use this typedef in all cases
// and expect it to be equal to boost::tuples::null_type
typedef boost::tuples::null_type null_type;
enum {length = boost::tuples::length<internal_tuple_type>::value};
// Return the element at the Indext'th position in the typelist.
// If the index is not less than the tuple length, it returns
// null_type.
template<int Index>
struct at :
boost::mpl::eval_if_c<
Index <
boost::tuples::length<typename tuple_traits::internal_tuple_type>::value,
boost::tuples::element<Index, typename tuple_traits::internal_tuple_type>,
boost::mpl::identity<typename tuple_traits::null_type> >{};
typedef typename make_as_tuple<internal_tuple_type>::type
as_tuple;
typedef typename make_result_type<internal_tuple_type>::type as_result;
};
template<typename T>
struct is_tuple_traits : boost::is_base_of<tuple_traits_tag, T> {};
} }
#endif