blob: 0c40b016436ce2a77f79ba2146c79cb8f2f191c9 [file] [log] [blame]
//[ FutureGroup
// Copyright 2008 Eric Niebler. 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)
//
// This is an example of using Proto transforms to implement
// Howard Hinnant's future group proposal.
#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/include/as_vector.hpp>
#include <boost/fusion/include/joint_view.hpp>
#include <boost/fusion/include/single_view.hpp>
#include <boost/proto/core.hpp>
#include <boost/proto/transform.hpp>
namespace mpl = boost::mpl;
namespace proto = boost::proto;
namespace fusion = boost::fusion;
using proto::_;
template<class L,class R>
struct pick_left
{
BOOST_MPL_ASSERT((boost::is_same<L, R>));
typedef L type;
};
// Work-arounds for Microsoft Visual C++ 7.1
#if BOOST_WORKAROUND(BOOST_MSVC, == 1310)
#define FutureGroup(x) proto::call<FutureGroup(x)>
#endif
// Define the grammar of future group expression, as well as a
// transform to turn them into a Fusion sequence of the correct
// type.
struct FutureGroup
: proto::or_<
// terminals become a single-element Fusion sequence
proto::when<
proto::terminal<_>
, fusion::single_view<proto::_value>(proto::_value)
>
// (a && b) becomes a concatenation of the sequence
// from 'a' and the one from 'b':
, proto::when<
proto::logical_and<FutureGroup, FutureGroup>
, fusion::joint_view<
boost::add_const<FutureGroup(proto::_left) >
, boost::add_const<FutureGroup(proto::_right) >
>(FutureGroup(proto::_left), FutureGroup(proto::_right))
>
// (a || b) becomes the sequence for 'a', so long
// as it is the same as the sequence for 'b'.
, proto::when<
proto::logical_or<FutureGroup, FutureGroup>
, pick_left<
FutureGroup(proto::_left)
, FutureGroup(proto::_right)
>(FutureGroup(proto::_left))
>
>
{};
#if BOOST_WORKAROUND(BOOST_MSVC, == 1310)
#undef FutureGroup
#endif
template<class E>
struct future_expr;
struct future_dom
: proto::domain<proto::generator<future_expr>, FutureGroup>
{};
// Expressions in the future group domain have a .get()
// member function that (ostensibly) blocks for the futures
// to complete and returns the results in an appropriate
// tuple.
template<class E>
struct future_expr
: proto::extends<E, future_expr<E>, future_dom>
{
explicit future_expr(E const &e)
: proto::extends<E, future_expr<E>, future_dom>(e)
{}
typename fusion::result_of::as_vector<
typename boost::result_of<FutureGroup(E,int,int)>::type
>::type
get() const
{
int i = 0;
return fusion::as_vector(FutureGroup()(*this, i, i));
}
};
// The future<> type has an even simpler .get()
// member function.
template<class T>
struct future
: future_expr<typename proto::terminal<T>::type>
{
future(T const &t = T())
: future_expr<typename proto::terminal<T>::type>(
proto::terminal<T>::type::make(t)
)
{}
T get() const
{
return proto::value(*this);
}
};
// TEST CASES
struct A {};
struct B {};
struct C {};
int main()
{
using fusion::vector;
future<A> a;
future<B> b;
future<C> c;
future<vector<A,B> > ab;
// Verify that various future groups have the
// correct return types.
A t0 = a.get();
vector<A, B, C> t1 = (a && b && c).get();
vector<A, C> t2 = ((a || a) && c).get();
vector<A, B, C> t3 = ((a && b || a && b) && c).get();
vector<vector<A, B>, C> t4 = ((ab || ab) && c).get();
return 0;
}
//]