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