summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/proto/example/futures.cpp
blob: 29e77d6ee1f148f75d38f8475848f6d5084d5b76 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//[ 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;
}
//]