summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/proto/test/lambda.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/proto/test/lambda.cpp')
-rw-r--r--src/boost/libs/proto/test/lambda.cpp188
1 files changed, 188 insertions, 0 deletions
diff --git a/src/boost/libs/proto/test/lambda.cpp b/src/boost/libs/proto/test/lambda.cpp
new file mode 100644
index 00000000..807f7cdb
--- /dev/null
+++ b/src/boost/libs/proto/test/lambda.cpp
@@ -0,0 +1,188 @@
+///////////////////////////////////////////////////////////////////////////////
+// lambda.hpp
+//
+// Copyright 2008 Eric Niebler. Distributed under the Boost
+// Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#include <sstream>
+#include <boost/mpl/int.hpp>
+#include <boost/mpl/min_max.hpp>
+#include <boost/mpl/eval_if.hpp>
+#include <boost/mpl/identity.hpp>
+#include <boost/mpl/next_prior.hpp>
+#include <boost/fusion/tuple.hpp>
+#include <boost/typeof/typeof.hpp>
+#include <boost/typeof/std/sstream.hpp>
+#include <boost/typeof/std/ostream.hpp>
+#include <boost/typeof/std/iostream.hpp>
+#include <boost/type_traits/add_const.hpp>
+#include <boost/type_traits/add_reference.hpp>
+#include <boost/proto/core.hpp>
+#include <boost/proto/context.hpp>
+#include <boost/proto/transform.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/test/floating_point_comparison.hpp>
+
+using namespace boost;
+
+// Forward declaration of the lambda expression wrapper
+template<typename T>
+struct lambda;
+
+struct lambda_domain
+ : proto::domain<proto::pod_generator<lambda> >
+{};
+
+template<typename I>
+struct placeholder
+{
+ typedef I arity;
+};
+
+template<typename T>
+struct placeholder_arity
+{
+ typedef typename T::arity type;
+};
+
+namespace grammar
+{
+ using namespace proto;
+
+ // The lambda grammar, with the transforms for calculating the max arity
+ struct Lambda
+ : or_<
+ when< terminal< placeholder<_> >, mpl::next<placeholder_arity<_value> >() >
+ , when< terminal<_>, mpl::int_<0>() >
+ , when< nary_expr<_, vararg<_> >, fold<_, mpl::int_<0>(), mpl::max<Lambda,_state>()> >
+ >
+ {};
+}
+
+// simple wrapper for calculating a lambda expression's arity.
+template<typename Expr>
+struct lambda_arity
+ : boost::result_of<grammar::Lambda(Expr, mpl::void_, mpl::void_)>
+{};
+
+// The lambda context is the same as the default context
+// with the addition of special handling for lambda placeholders
+template<typename Tuple>
+struct lambda_context
+ : proto::callable_context<lambda_context<Tuple> const>
+{
+ lambda_context(Tuple const &args)
+ : args_(args)
+ {}
+
+ template<typename Sig>
+ struct result;
+
+ template<typename This, typename I>
+ struct result<This(proto::tag::terminal, placeholder<I> const &)>
+ : fusion::result_of::at<Tuple, I>
+ {};
+
+ template<typename I>
+ typename fusion::result_of::at<Tuple, I>::type
+ operator ()(proto::tag::terminal, placeholder<I> const &) const
+ {
+ return fusion::at<I>(this->args_);
+ }
+
+ Tuple args_;
+};
+
+// The lambda<> expression wrapper makes expressions polymorphic
+// function objects
+template<typename T>
+struct lambda
+{
+ BOOST_PROTO_BASIC_EXTENDS(T, lambda<T>, lambda_domain)
+ BOOST_PROTO_EXTENDS_ASSIGN()
+ BOOST_PROTO_EXTENDS_SUBSCRIPT()
+
+ // Careful not to evaluate the return type of the nullary function
+ // unless we have a nullary lambda!
+ typedef typename mpl::eval_if<
+ typename lambda_arity<T>::type
+ , mpl::identity<void>
+ , proto::result_of::eval<T const, lambda_context<fusion::tuple<> > >
+ >::type nullary_type;
+
+ // Define our operator () that evaluates the lambda expression.
+ nullary_type operator ()() const
+ {
+ fusion::tuple<> args;
+ lambda_context<fusion::tuple<> > ctx(args);
+ return proto::eval(*this, ctx);
+ }
+
+ #define M0(N, typename_A, A_const_ref, A_const_ref_a, ref_a) \
+ template<typename_A(N)> \
+ typename proto::result_of::eval<T const, lambda_context<fusion::tuple<A_const_ref(N)> > >::type \
+ operator ()(A_const_ref_a(N)) const \
+ { \
+ fusion::tuple<A_const_ref(N)> args(ref_a(N)); \
+ lambda_context<fusion::tuple<A_const_ref(N)> > ctx(args); \
+ return proto::eval(*this, ctx); \
+ } \
+ /**/
+ BOOST_PROTO_REPEAT_FROM_TO(1, 4, M0)
+ #undef M0
+};
+
+// Define some lambda placeholders
+lambda<proto::terminal<placeholder<mpl::int_<0> > >::type> const _1 = {{}};
+lambda<proto::terminal<placeholder<mpl::int_<1> > >::type> const _2 = {{}};
+lambda<proto::terminal<placeholder<mpl::int_<3> > >::type> const _3 = {{}};
+
+template<typename T>
+lambda<typename proto::terminal<T>::type> const val(T const &t)
+{
+ lambda<typename proto::terminal<T>::type> that = {{t}};
+ return that;
+}
+
+template<typename T>
+lambda<typename proto::terminal<T &>::type> const var(T &t)
+{
+ lambda<typename proto::terminal<T &>::type> that = {{t}};
+ return that;
+}
+
+void test_lambda()
+{
+ BOOST_CHECK_EQUAL(11, ( (_1 + 2) / 4 )(42));
+ BOOST_CHECK_EQUAL(-11, ( (-(_1 + 2)) / 4 )(42));
+ BOOST_CHECK_CLOSE(2.58, ( (4 - _2) * 3 )(42, 3.14), 0.1);
+
+ // check non-const ref terminals
+ std::stringstream sout;
+ (sout << _1 << " -- " << _2)(42, "Life, the Universe and Everything!");
+ BOOST_CHECK_EQUAL("42 -- Life, the Universe and Everything!", sout.str());
+
+ // check nullary lambdas
+ BOOST_CHECK_EQUAL(3, (val(1) + val(2))());
+
+ // check array indexing for kicks
+ int integers[5] = {0};
+ (var(integers)[2] = 2)();
+ (var(integers)[_1] = _1)(3);
+ BOOST_CHECK_EQUAL(2, integers[2]);
+ BOOST_CHECK_EQUAL(3, integers[3]);
+}
+
+using namespace unit_test;
+///////////////////////////////////////////////////////////////////////////////
+// init_unit_test_suite
+//
+test_suite* init_unit_test_suite( int argc, char* argv[] )
+{
+ test_suite *test = BOOST_TEST_SUITE("test expression template domains");
+
+ test->add(BOOST_TEST_CASE(&test_lambda));
+
+ return test;
+}