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 //[ vec3
7 #include <boost/yap/yap.hpp>
8 
9 #include <array>
10 #include <iostream>
11 
12 
13 struct take_nth
14 {
operator ()take_nth15     auto operator() (boost::yap::terminal<boost::yap::expression, std::array<int, 3>> const & expr)
16     {
17         int x = boost::yap::value(expr)[n];
18         // The move forces the terminal to store the value of x, not a
19         // reference.
20         return boost::yap::make_terminal(std::move(x));
21     }
22 
23     std::size_t n;
24 };
25 
26 // Since this example doesn't constrain the operators defined on its
27 // expressions, we can just use boost::yap::expression<> as the expression
28 // template.
29 using vec3_terminal = boost::yap::expression<
30     boost::yap::expr_kind::terminal,
31     boost::hana::tuple<std::array<int, 3>>
32 >;
33 
34 // Customize the terminal type we use by adding index and assignment
35 // operations.
36 struct vec3 : vec3_terminal
37 {
vec3vec338     explicit vec3 (int i = 0, int j = 0, int k = 0)
39     {
40         (*this)[0] = i;
41         (*this)[1] = j;
42         (*this)[2] = k;
43     }
44 
vec3vec345     explicit vec3 (std::array<int, 3> a)
46     {
47         (*this)[0] = a[0];
48         (*this)[1] = a[1];
49         (*this)[2] = a[2];
50     }
51 
operator []vec352     int & operator[] (std::ptrdiff_t i)
53     { return boost::yap::value(*this)[i]; }
54 
operator []vec355     int const & operator[] (std::ptrdiff_t i) const
56     { return boost::yap::value(*this)[i]; }
57 
58     template <typename T>
operator =vec359     vec3 & operator= (T const & t)
60     {
61         decltype(auto) expr = boost::yap::as_expr(t);
62         (*this)[0] = boost::yap::evaluate(boost::yap::transform(expr, take_nth{0}));
63         (*this)[1] = boost::yap::evaluate(boost::yap::transform(expr, take_nth{1}));
64         (*this)[2] = boost::yap::evaluate(boost::yap::transform(expr, take_nth{2}));
65         return *this;
66     }
67 
printvec368     void print() const
69     {
70         std::cout << '{' << (*this)[0]
71                   << ", " << (*this)[1]
72                   << ", " << (*this)[2]
73                   << '}' << std::endl;
74     }
75 };
76 
77 // This is a stateful transform that keeps a running count of the terminals it
78 // has seen.
79 struct count_leaves_impl
80 {
operator ()count_leaves_impl81     auto operator() (vec3_terminal const & expr)
82     {
83         value += 1;
84         return expr;
85     }
86 
87     int value = 0;
88 };
89 
90 template <typename Expr>
count_leaves(Expr const & expr)91 int count_leaves (Expr const & expr)
92 {
93     count_leaves_impl impl;
94     boost::yap::transform(boost::yap::as_expr(expr), impl);
95     return impl.value;
96 }
97 
98 
main()99 int main()
100 {
101     vec3 a, b, c;
102 
103     c = 4;
104 
105     b[0] = -1;
106     b[1] = -2;
107     b[2] = -3;
108 
109     a = b + c;
110 
111     a.print();
112 
113     vec3 d;
114     auto expr1 = b + c;
115     d = expr1;
116     d.print();
117 
118     int num = count_leaves(expr1);
119     std::cout << num << std::endl;
120 
121     num = count_leaves(b + 3 * c);
122     std::cout << num << std::endl;
123 
124     num = count_leaves(b + c * d);
125     std::cout << num << std::endl;
126 
127     return 0;
128 }
129 //]
130