123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- //[ 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)
- : future_expr::proto_extends(e)
- {}
- typename fusion::result_of::as_vector<
- typename boost::result_of<FutureGroup(E)>::type
- >::type
- get() const
- {
- return fusion::as_vector(FutureGroup()(*this));
- }
- };
- // 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::proto_derived_expr(future::proto_base_expr::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;
- }
- //]
|