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 &&.
14template <boost::yap::expr_kind Kind, typename Tuple>
15struct future_expr
16{
17 static boost::yap::expr_kind const kind = Kind;
18
19 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
29BOOST_YAP_USER_BINARY_OPERATOR(logical_or, future_expr, future_expr)
30BOOST_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.
34template <typename T>
35struct future :
36 future_expr<boost::yap::expr_kind::terminal, boost::hana::tuple<T>>
37{
38 future (T const & t = T()) :
39 future_expr<boost::yap::expr_kind::terminal, boost::hana::tuple<T>> (boost::hana::tuple<T>{t})
40 {}
41
42 T get () const
43 { return boost::yap::value(*this); }
44};
45
46template <typename T>
47using remove_cv_ref_t = std::remove_cv_t<std::remove_reference_t<T>>;
48
49// A transform that flattens future expressions into a tuple.
50struct future_transform
51{
52 // Transform a terminal into its contained tuple.
53 template <typename T>
54 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>
66 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>
81 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
97template <boost::yap::expr_kind Kind, typename Tuple>
98auto future_expr<Kind, Tuple>::get () const
99{ return boost::yap::transform(*this, future_transform{}); }
100
101
102// TEST CASES
103struct A {};
104struct B {};
105struct C {};
106
107// Called "vector" just so the code in main() will match the original Proto
108// example.
109template <typename ...T>
110using vector = boost::hana::tuple<T...>;
111
112int 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

source code of boost/libs/yap/example/future_group.cpp