• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //[ FutureGroup
2 //  Copyright 2008 Eric Niebler. Distributed under the Boost
3 //  Software License, Version 1.0. (See accompanying file
4 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 //
6 // This is an example of using Proto transforms to implement
7 // Howard Hinnant's future group proposal.
8 
9 #include <boost/fusion/include/vector.hpp>
10 #include <boost/fusion/include/as_vector.hpp>
11 #include <boost/fusion/include/joint_view.hpp>
12 #include <boost/fusion/include/single_view.hpp>
13 #include <boost/proto/core.hpp>
14 #include <boost/proto/transform.hpp>
15 namespace mpl = boost::mpl;
16 namespace proto = boost::proto;
17 namespace fusion = boost::fusion;
18 using proto::_;
19 
20 template<class L,class R>
21 struct pick_left
22 {
23     BOOST_MPL_ASSERT((boost::is_same<L, R>));
24     typedef L type;
25 };
26 
27 // Work-arounds for Microsoft Visual C++ 7.1
28 #if BOOST_WORKAROUND(BOOST_MSVC, == 1310)
29 #define FutureGroup(x) proto::call<FutureGroup(x)>
30 #endif
31 
32 // Define the grammar of future group expression, as well as a
33 // transform to turn them into a Fusion sequence of the correct
34 // type.
35 struct FutureGroup
36   : proto::or_<
37         // terminals become a single-element Fusion sequence
38         proto::when<
39             proto::terminal<_>
40           , fusion::single_view<proto::_value>(proto::_value)
41         >
42         // (a && b) becomes a concatenation of the sequence
43         // from 'a' and the one from 'b':
44       , proto::when<
45             proto::logical_and<FutureGroup, FutureGroup>
46           , fusion::joint_view<
47                 boost::add_const<FutureGroup(proto::_left) >
48               , boost::add_const<FutureGroup(proto::_right) >
49             >(FutureGroup(proto::_left), FutureGroup(proto::_right))
50         >
51         // (a || b) becomes the sequence for 'a', so long
52         // as it is the same as the sequence for 'b'.
53       , proto::when<
54             proto::logical_or<FutureGroup, FutureGroup>
55           , pick_left<
56                 FutureGroup(proto::_left)
57               , FutureGroup(proto::_right)
58             >(FutureGroup(proto::_left))
59         >
60     >
61 {};
62 
63 #if BOOST_WORKAROUND(BOOST_MSVC, == 1310)
64 #undef FutureGroup
65 #endif
66 
67 template<class E>
68 struct future_expr;
69 
70 struct future_dom
71   : proto::domain<proto::generator<future_expr>, FutureGroup>
72 {};
73 
74 // Expressions in the future group domain have a .get()
75 // member function that (ostensibly) blocks for the futures
76 // to complete and returns the results in an appropriate
77 // tuple.
78 template<class E>
79 struct future_expr
80   : proto::extends<E, future_expr<E>, future_dom>
81 {
future_exprfuture_expr82     explicit future_expr(E const &e)
83       : future_expr::proto_extends(e)
84     {}
85 
86     typename fusion::result_of::as_vector<
87         typename boost::result_of<FutureGroup(E)>::type
88     >::type
getfuture_expr89     get() const
90     {
91         return fusion::as_vector(FutureGroup()(*this));
92     }
93 };
94 
95 // The future<> type has an even simpler .get()
96 // member function.
97 template<class T>
98 struct future
99   : future_expr<typename proto::terminal<T>::type>
100 {
futurefuture101     future(T const &t = T())
102       : future::proto_derived_expr(future::proto_base_expr::make(t))
103     {}
104 
getfuture105     T get() const
106     {
107         return proto::value(*this);
108     }
109 };
110 
111 // TEST CASES
112 struct A {};
113 struct B {};
114 struct C {};
115 
main()116 int main()
117 {
118     using fusion::vector;
119     future<A> a;
120     future<B> b;
121     future<C> c;
122     future<vector<A,B> > ab;
123 
124     // Verify that various future groups have the
125     // correct return types.
126     A                       t0 = a.get();
127     vector<A, B, C>         t1 = (a && b && c).get();
128     vector<A, C>            t2 = ((a || a) && c).get();
129     vector<A, B, C>         t3 = ((a && b || a && b) && c).get();
130     vector<vector<A, B>, C> t4 = ((ab || ab) && c).get();
131 
132     return 0;
133 }
134 //]
135