• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2016-2018 T. Zachary Laine
2 //
3 // Distributed under the Boost Software License, Version 1.0. (See
4 // accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 //[ future_group
7 #include <boost/yap/algorithm.hpp>
8 
9 #include <boost/hana/concat.hpp>
10 
11 
12 // A custom expression template for future groups.  It supports operators ||
13 // and &&.
14 template <boost::yap::expr_kind Kind, typename Tuple>
15 struct future_expr
16 {
17     static boost::yap::expr_kind const kind = Kind;
18 
future_exprfuture_expr19     future_expr (Tuple && tuple) :
20         elements (std::forward<Tuple &&>(tuple))
21     {}
22 
23     Tuple elements;
24 
25     // Returns the transformed/flattened expression.
26     auto get () const;
27 };
28 
29 BOOST_YAP_USER_BINARY_OPERATOR(logical_or, future_expr, future_expr)
30 BOOST_YAP_USER_BINARY_OPERATOR(logical_and, future_expr, future_expr)
31 
32 // A special-cased future terminal that matches the semantics from the
33 // original Proto example.
34 template <typename T>
35 struct future :
36     future_expr<boost::yap::expr_kind::terminal, boost::hana::tuple<T>>
37 {
futurefuture38     future (T const & t = T()) :
39         future_expr<boost::yap::expr_kind::terminal, boost::hana::tuple<T>> (boost::hana::tuple<T>{t})
40     {}
41 
getfuture42     T get () const
43     { return boost::yap::value(*this); }
44 };
45 
46 template <typename T>
47 using remove_cv_ref_t = std::remove_cv_t<std::remove_reference_t<T>>;
48 
49 // A transform that flattens future expressions into a tuple.
50 struct future_transform
51 {
52     // Transform a terminal into its contained tuple.
53     template <typename T>
operator ()future_transform54     auto operator() (
55         future_expr<
56             boost::yap::expr_kind::terminal,
57             boost::hana::tuple<T>
58         > const & term
59     ) {
60         return term.elements;
61     }
62 
63 //[ expr_xform
64     // Transform left || right -> transform(left).
65     template <typename T, typename U>
operator ()future_transform66     auto operator() (
67         future_expr<
68             boost::yap::expr_kind::logical_or,
69             boost::hana::tuple<T, U>
70         > const & or_expr
71     ) {
72         // Recursively transform the left side, and return the result.
73         // Without the recursion, we might return a terminal expression here
74         // insead of a tuple.
75         return boost::yap::transform(boost::yap::left(or_expr), *this);
76     }
77 //]
78 
79     // Transform left && right -> concat(transform(left), transform(right)).
80     template <typename T, typename U>
operator ()future_transform81     auto operator() (
82         future_expr<
83             boost::yap::expr_kind::logical_and,
84             boost::hana::tuple<T, U>
85         > const & and_expr
86     ) {
87         // Recursively transform each side, then combine the resulting tuples
88         // into a single tuple result.
89         return boost::hana::concat(
90             boost::yap::transform(boost::yap::left(and_expr), *this),
91             boost::yap::transform(boost::yap::right(and_expr), *this)
92         );
93     }
94 };
95 
96 
97 template <boost::yap::expr_kind Kind, typename Tuple>
get() const98 auto future_expr<Kind, Tuple>::get () const
99 { return boost::yap::transform(*this, future_transform{}); }
100 
101 
102 // TEST CASES
103 struct A {};
104 struct B {};
105 struct C {};
106 
107 // Called "vector" just so the code in main() will match the original Proto
108 // example.
109 template <typename ...T>
110 using vector = boost::hana::tuple<T...>;
111 
main()112 int main()
113 {
114     future<A> a;
115     future<B> b;
116     future<C> c;
117     future<vector<A,B> > ab;
118 
119     // Verify that various future groups have the
120     // correct return types.
121     A                       t0 = a.get();
122     vector<A, B, C>         t1 = (a && b && c).get();
123     vector<A, C>            t2 = ((a || a) && c).get();
124     vector<A, B, C>         t3 = ((a && b || a && b) && c).get();
125     vector<vector<A, B>, C> t4 = ((ab || ab) && c).get();
126 
127     return 0;
128 }
129 //]
130