Files
SingularityViewer/libraries/include/boost/coroutine/future.hpp
2010-04-02 02:48:44 -03:00

306 lines
8.9 KiB
C++

// 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