Imported existing code
This commit is contained in:
302
libraries/include/boost/coroutine/coroutine.hpp
Normal file
302
libraries/include/boost/coroutine/coroutine.hpp
Normal 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
|
||||
34
libraries/include/boost/coroutine/detail/arg_max.hpp
Normal file
34
libraries/include/boost/coroutine/detail/arg_max.hpp
Normal 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
|
||||
70
libraries/include/boost/coroutine/detail/argument_packer.hpp
Normal file
70
libraries/include/boost/coroutine/detail/argument_packer.hpp
Normal 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
|
||||
134
libraries/include/boost/coroutine/detail/argument_unpacker.hpp
Normal file
134
libraries/include/boost/coroutine/detail/argument_unpacker.hpp
Normal 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
|
||||
123
libraries/include/boost/coroutine/detail/call_impl.hpp
Normal file
123
libraries/include/boost/coroutine/detail/call_impl.hpp
Normal 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
|
||||
416
libraries/include/boost/coroutine/detail/context_base.hpp
Normal file
416
libraries/include/boost/coroutine/detail/context_base.hpp
Normal 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
|
||||
285
libraries/include/boost/coroutine/detail/context_linux.hpp
Normal file
285
libraries/include/boost/coroutine/detail/context_linux.hpp
Normal 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
|
||||
231
libraries/include/boost/coroutine/detail/context_posix.hpp
Normal file
231
libraries/include/boost/coroutine/detail/context_posix.hpp
Normal 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
|
||||
181
libraries/include/boost/coroutine/detail/context_windows.hpp
Normal file
181
libraries/include/boost/coroutine/detail/context_windows.hpp
Normal 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
|
||||
103
libraries/include/boost/coroutine/detail/coroutine_accessor.hpp
Normal file
103
libraries/include/boost/coroutine/detail/coroutine_accessor.hpp
Normal 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
|
||||
276
libraries/include/boost/coroutine/detail/coroutine_impl.hpp
Normal file
276
libraries/include/boost/coroutine/detail/coroutine_impl.hpp
Normal 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
61
libraries/include/boost/coroutine/detail/fix_result.hpp
Normal file
61
libraries/include/boost/coroutine/detail/fix_result.hpp
Normal 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
|
||||
140
libraries/include/boost/coroutine/detail/future_impl.hpp
Normal file
140
libraries/include/boost/coroutine/detail/future_impl.hpp
Normal 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
|
||||
84
libraries/include/boost/coroutine/detail/has_swap.hpp
Normal file
84
libraries/include/boost/coroutine/detail/has_swap.hpp
Normal 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
|
||||
42
libraries/include/boost/coroutine/detail/index.hpp
Normal file
42
libraries/include/boost/coroutine/detail/index.hpp
Normal 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
|
||||
62
libraries/include/boost/coroutine/detail/is_callable.hpp
Normal file
62
libraries/include/boost/coroutine/detail/is_callable.hpp
Normal 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
|
||||
@@ -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
|
||||
68
libraries/include/boost/coroutine/detail/noreturn.hpp
Normal file
68
libraries/include/boost/coroutine/detail/noreturn.hpp
Normal 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
|
||||
161
libraries/include/boost/coroutine/detail/posix_utility.hpp
Normal file
161
libraries/include/boost/coroutine/detail/posix_utility.hpp
Normal 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
|
||||
274
libraries/include/boost/coroutine/detail/self.hpp
Normal file
274
libraries/include/boost/coroutine/detail/self.hpp
Normal 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
|
||||
67
libraries/include/boost/coroutine/detail/signal.hpp
Normal file
67
libraries/include/boost/coroutine/detail/signal.hpp
Normal 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
|
||||
56
libraries/include/boost/coroutine/detail/signature.hpp
Normal file
56
libraries/include/boost/coroutine/detail/signature.hpp
Normal 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
|
||||
38
libraries/include/boost/coroutine/detail/swap_context.hpp
Normal file
38
libraries/include/boost/coroutine/detail/swap_context.hpp
Normal 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
|
||||
102
libraries/include/boost/coroutine/detail/wait_impl.hpp
Normal file
102
libraries/include/boost/coroutine/detail/wait_impl.hpp
Normal 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
|
||||
@@ -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
|
||||
80
libraries/include/boost/coroutine/exception.hpp
Normal file
80
libraries/include/boost/coroutine/exception.hpp
Normal 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
|
||||
305
libraries/include/boost/coroutine/future.hpp
Normal file
305
libraries/include/boost/coroutine/future.hpp
Normal 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
|
||||
|
||||
155
libraries/include/boost/coroutine/generator.hpp
Normal file
155
libraries/include/boost/coroutine/generator.hpp
Normal 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
|
||||
322
libraries/include/boost/coroutine/move.hpp
Normal file
322
libraries/include/boost/coroutine/move.hpp
Normal 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
|
||||
72
libraries/include/boost/coroutine/shared_coroutine.hpp
Normal file
72
libraries/include/boost/coroutine/shared_coroutine.hpp
Normal 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
|
||||
170
libraries/include/boost/coroutine/tuple_traits.hpp
Normal file
170
libraries/include/boost/coroutine/tuple_traits.hpp
Normal 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
|
||||
Reference in New Issue
Block a user