• 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 //[ tarray
7 #include <boost/yap/algorithm.hpp>
8 #include <boost/yap/print.hpp>
9 
10 #include <array>
11 #include <iostream>
12 
13 
14 template <boost::yap::expr_kind Kind, typename Tuple>
15 struct tarray_expr;
16 
17 
18 struct take_nth
19 {
20     boost::yap::terminal<tarray_expr, int>
21     operator() (boost::yap::terminal<tarray_expr, std::array<int, 3>> const & expr);
22 
23     std::size_t n;
24 };
25 
26 // Another custom expression template.  In this case, we static_assert() that
27 // it only gets instantiated with terminals with pre-approved value types.
28 template <boost::yap::expr_kind Kind, typename Tuple>
29 struct tarray_expr
30 {
31     // Make sure that, if this expression is a terminal, its value is one we
32     // want to support.  Note that the presence of expr_kind::expr_ref makes
33     // life slightly more difficult; we have to account for int const & and
34     // int & as well as int.
35     static_assert(
36         Kind != boost::yap::expr_kind::terminal ||
37         std::is_same<Tuple, boost::hana::tuple<int const &>>{} ||
38         std::is_same<Tuple, boost::hana::tuple<int &>>{} ||
39         std::is_same<Tuple, boost::hana::tuple<int>>{} ||
40         std::is_same<Tuple, boost::hana::tuple<std::array<int, 3>>>{},
41         "tarray_expr instantiated with an unsupported terminal type."
42     );
43 
44     static const boost::yap::expr_kind kind = Kind;
45 
46     Tuple elements;
47 
operator []tarray_expr48     int operator[] (std::size_t n) const
49     { return boost::yap::evaluate(boost::yap::transform(*this, take_nth{n})); }
50 };
51 
52 // Define operators +, -, *, and /.
BOOST_YAP_USER_BINARY_OPERATOR(plus,tarray_expr,tarray_expr)53 BOOST_YAP_USER_BINARY_OPERATOR(plus, tarray_expr, tarray_expr)
54 BOOST_YAP_USER_BINARY_OPERATOR(minus, tarray_expr, tarray_expr)
55 BOOST_YAP_USER_BINARY_OPERATOR(multiplies, tarray_expr, tarray_expr)
56 BOOST_YAP_USER_BINARY_OPERATOR(divides, tarray_expr, tarray_expr)
57 
58 
59 boost::yap::terminal<tarray_expr, int>
60 take_nth::operator() (boost::yap::terminal<tarray_expr, std::array<int, 3>> const & expr)
61 {
62     int x = boost::yap::value(expr)[n];
63     // Again, this is the move hack to get x into the resulting terminal as a
64     // value instead of a reference.
65     return boost::yap::make_terminal<tarray_expr>(std::move(x));
66 }
67 
68 
69 // Stream-out operators for the two kinds of terminals we support.
70 
operator <<(std::ostream & os,boost::yap::terminal<tarray_expr,int> expr)71 std::ostream & operator<< (std::ostream & os, boost::yap::terminal<tarray_expr, int> expr)
72 { return os << '{' << boost::yap::value(expr) << '}'; }
73 
operator <<(std::ostream & os,boost::yap::terminal<tarray_expr,std::array<int,3>> expr)74 std::ostream & operator<< (std::ostream & os, boost::yap::terminal<tarray_expr, std::array<int, 3>> expr)
75 {
76     std::array<int, 3> const & a = boost::yap::value(expr);
77     return os << '{' << a[0] << ", " << a[1] << ", " << a[2] << '}';
78 }
79 
80 // Stream-out operators for general expressions.  Note that we have to treat
81 // the reference case separately; this also could have been done using
82 // constexpr if in a single function template.
83 
84 template <typename Tuple>
operator <<(std::ostream & os,tarray_expr<boost::yap::expr_kind::expr_ref,Tuple> const & expr)85 std::ostream & operator<< (std::ostream & os, tarray_expr<boost::yap::expr_kind::expr_ref, Tuple> const & expr)
86 { return os << boost::yap::deref(expr); }
87 
88 template <boost::yap::expr_kind Kind, typename Tuple>
operator <<(std::ostream & os,tarray_expr<Kind,Tuple> const & expr)89 std::ostream & operator<< (std::ostream & os, tarray_expr<Kind, Tuple> const & expr)
90 {
91     if (Kind == boost::yap::expr_kind::plus || Kind == boost::yap::expr_kind::minus)
92         os << '(';
93     os << boost::yap::left(expr) << " " << op_string(Kind) << " " << boost::yap::right(expr);
94     if (Kind == boost::yap::expr_kind::plus || Kind == boost::yap::expr_kind::minus)
95         os << ')';
96     return os;
97 }
98 
99 
100 // Since we want different behavior on terminals than on other kinds of
101 // expressions, we create a custom type that does so.
102 struct tarray :
103     tarray_expr<
104         boost::yap::expr_kind::terminal,
105         boost::hana::tuple<std::array<int, 3>>
106     >
107 {
tarraytarray108     explicit tarray (int i = 0, int j = 0, int k = 0)
109     {
110         (*this)[0] = i;
111         (*this)[1] = j;
112         (*this)[2] = k;
113     }
114 
tarraytarray115     explicit tarray (std::array<int, 3> a)
116     {
117         (*this)[0] = a[0];
118         (*this)[1] = a[1];
119         (*this)[2] = a[2];
120     }
121 
operator []tarray122     int & operator[] (std::ptrdiff_t i)
123     { return boost::yap::value(*this)[i]; }
124 
operator []tarray125     int const & operator[] (std::ptrdiff_t i) const
126     { return boost::yap::value(*this)[i]; }
127 
128     template <typename T>
operator =tarray129     tarray & operator= (T const & t)
130     {
131         // We use as_expr() here to make sure that the value passed to
132         // assign() is an expression.  as_expr() simply forwards expressions
133         // through, and wraps non-expressions as terminals.
134         return assign(boost::yap::as_expr< ::tarray_expr>(t));
135     }
136 
137     template <typename Expr>
printAssigntarray138     tarray & printAssign (Expr const & expr)
139     {
140         *this = expr;
141         std::cout << *this << " = " << expr << std::endl;
142         return *this;
143     }
144 
145 private:
146     template <typename Expr>
assigntarray147     tarray & assign (Expr const & expr)
148     {
149         (*this)[0] = expr[0];
150         (*this)[1] = expr[1];
151         (*this)[2] = expr[2];
152         return *this;
153     }
154 };
155 
156 
main()157 int main()
158 {
159     tarray a(3,1,2);
160 
161     tarray b;
162 
163     std::cout << a << std::endl;
164     std::cout << b << std::endl;
165 
166     b[0] = 7; b[1] = 33; b[2] = -99;
167 
168     tarray c(a);
169 
170     std::cout << c << std::endl;
171 
172     a = 0;
173 
174     std::cout << a << std::endl;
175     std::cout << b << std::endl;
176     std::cout << c << std::endl;
177 
178     a = b + c;
179 
180     std::cout << a << std::endl;
181 
182     a.printAssign(b+c*(b + 3*c));
183 
184     return 0;
185 }
186 //]
187