]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/proto/test/lambda.cpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / proto / test / lambda.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // lambda.hpp
3 //
4 // Copyright 2008 Eric Niebler. Distributed under the Boost
5 // Software License, Version 1.0. (See accompanying file
6 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7
8 #include <sstream>
9 #include <boost/mpl/int.hpp>
10 #include <boost/mpl/min_max.hpp>
11 #include <boost/mpl/eval_if.hpp>
12 #include <boost/mpl/identity.hpp>
13 #include <boost/mpl/next_prior.hpp>
14 #include <boost/fusion/tuple.hpp>
15 #include <boost/typeof/typeof.hpp>
16 #include <boost/typeof/std/sstream.hpp>
17 #include <boost/typeof/std/ostream.hpp>
18 #include <boost/typeof/std/iostream.hpp>
19 #include <boost/type_traits/add_const.hpp>
20 #include <boost/type_traits/add_reference.hpp>
21 #include <boost/proto/core.hpp>
22 #include <boost/proto/context.hpp>
23 #include <boost/proto/transform.hpp>
24 #include <boost/test/unit_test.hpp>
25 #include <boost/test/floating_point_comparison.hpp>
26
27 using namespace boost;
28
29 // Forward declaration of the lambda expression wrapper
30 template<typename T>
31 struct lambda;
32
33 struct lambda_domain
34 : proto::domain<proto::pod_generator<lambda> >
35 {};
36
37 template<typename I>
38 struct placeholder
39 {
40 typedef I arity;
41 };
42
43 template<typename T>
44 struct placeholder_arity
45 {
46 typedef typename T::arity type;
47 };
48
49 namespace grammar
50 {
51 using namespace proto;
52
53 // The lambda grammar, with the transforms for calculating the max arity
54 struct Lambda
55 : or_<
56 when< terminal< placeholder<_> >, mpl::next<placeholder_arity<_value> >() >
57 , when< terminal<_>, mpl::int_<0>() >
58 , when< nary_expr<_, vararg<_> >, fold<_, mpl::int_<0>(), mpl::max<Lambda,_state>()> >
59 >
60 {};
61 }
62
63 // simple wrapper for calculating a lambda expression's arity.
64 template<typename Expr>
65 struct lambda_arity
66 : boost::result_of<grammar::Lambda(Expr, mpl::void_, mpl::void_)>
67 {};
68
69 // The lambda context is the same as the default context
70 // with the addition of special handling for lambda placeholders
71 template<typename Tuple>
72 struct lambda_context
73 : proto::callable_context<lambda_context<Tuple> const>
74 {
75 lambda_context(Tuple const &args)
76 : args_(args)
77 {}
78
79 template<typename Sig>
80 struct result;
81
82 template<typename This, typename I>
83 struct result<This(proto::tag::terminal, placeholder<I> const &)>
84 : fusion::result_of::at<Tuple, I>
85 {};
86
87 template<typename I>
88 typename fusion::result_of::at<Tuple, I>::type
89 operator ()(proto::tag::terminal, placeholder<I> const &) const
90 {
91 return fusion::at<I>(this->args_);
92 }
93
94 Tuple args_;
95 };
96
97 // The lambda<> expression wrapper makes expressions polymorphic
98 // function objects
99 template<typename T>
100 struct lambda
101 {
102 BOOST_PROTO_BASIC_EXTENDS(T, lambda<T>, lambda_domain)
103 BOOST_PROTO_EXTENDS_ASSIGN()
104 BOOST_PROTO_EXTENDS_SUBSCRIPT()
105
106 // Careful not to evaluate the return type of the nullary function
107 // unless we have a nullary lambda!
108 typedef typename mpl::eval_if<
109 typename lambda_arity<T>::type
110 , mpl::identity<void>
111 , proto::result_of::eval<T const, lambda_context<fusion::tuple<> > >
112 >::type nullary_type;
113
114 // Define our operator () that evaluates the lambda expression.
115 nullary_type operator ()() const
116 {
117 fusion::tuple<> args;
118 lambda_context<fusion::tuple<> > ctx(args);
119 return proto::eval(*this, ctx);
120 }
121
122 #define M0(N, typename_A, A_const_ref, A_const_ref_a, ref_a) \
123 template<typename_A(N)> \
124 typename proto::result_of::eval<T const, lambda_context<fusion::tuple<A_const_ref(N)> > >::type \
125 operator ()(A_const_ref_a(N)) const \
126 { \
127 fusion::tuple<A_const_ref(N)> args(ref_a(N)); \
128 lambda_context<fusion::tuple<A_const_ref(N)> > ctx(args); \
129 return proto::eval(*this, ctx); \
130 } \
131 /**/
132 BOOST_PROTO_REPEAT_FROM_TO(1, 4, M0)
133 #undef M0
134 };
135
136 // Define some lambda placeholders
137 lambda<proto::terminal<placeholder<mpl::int_<0> > >::type> const _1 = {{}};
138 lambda<proto::terminal<placeholder<mpl::int_<1> > >::type> const _2 = {{}};
139 lambda<proto::terminal<placeholder<mpl::int_<3> > >::type> const _3 = {{}};
140
141 template<typename T>
142 lambda<typename proto::terminal<T>::type> const val(T const &t)
143 {
144 lambda<typename proto::terminal<T>::type> that = {{t}};
145 return that;
146 }
147
148 template<typename T>
149 lambda<typename proto::terminal<T &>::type> const var(T &t)
150 {
151 lambda<typename proto::terminal<T &>::type> that = {{t}};
152 return that;
153 }
154
155 void test_lambda()
156 {
157 BOOST_CHECK_EQUAL(11, ( (_1 + 2) / 4 )(42));
158 BOOST_CHECK_EQUAL(-11, ( (-(_1 + 2)) / 4 )(42));
159 BOOST_CHECK_CLOSE(2.58, ( (4 - _2) * 3 )(42, 3.14), 0.1);
160
161 // check non-const ref terminals
162 std::stringstream sout;
163 (sout << _1 << " -- " << _2)(42, "Life, the Universe and Everything!");
164 BOOST_CHECK_EQUAL("42 -- Life, the Universe and Everything!", sout.str());
165
166 // check nullary lambdas
167 BOOST_CHECK_EQUAL(3, (val(1) + val(2))());
168
169 // check array indexing for kicks
170 int integers[5] = {0};
171 (var(integers)[2] = 2)();
172 (var(integers)[_1] = _1)(3);
173 BOOST_CHECK_EQUAL(2, integers[2]);
174 BOOST_CHECK_EQUAL(3, integers[3]);
175 }
176
177 using namespace unit_test;
178 ///////////////////////////////////////////////////////////////////////////////
179 // init_unit_test_suite
180 //
181 test_suite* init_unit_test_suite( int argc, char* argv[] )
182 {
183 test_suite *test = BOOST_TEST_SUITE("test expression template domains");
184
185 test->add(BOOST_TEST_CASE(&test_lambda));
186
187 return test;
188 }