summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/proto/test/examples.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/proto/test/examples.cpp')
-rw-r--r--src/boost/libs/proto/test/examples.cpp498
1 files changed, 498 insertions, 0 deletions
diff --git a/src/boost/libs/proto/test/examples.cpp b/src/boost/libs/proto/test/examples.cpp
new file mode 100644
index 000000000..35769bca2
--- /dev/null
+++ b/src/boost/libs/proto/test/examples.cpp
@@ -0,0 +1,498 @@
+///////////////////////////////////////////////////////////////////////////////
+// examples.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 <iostream>
+#include <boost/config.hpp>
+#include <boost/mpl/min_max.hpp>
+#include <boost/proto/core.hpp>
+#include <boost/proto/transform.hpp>
+#include <boost/proto/functional/fusion.hpp>
+#include <boost/utility/result_of.hpp>
+#include <boost/fusion/include/cons.hpp>
+#include <boost/fusion/include/tuple.hpp>
+#include <boost/fusion/include/pop_front.hpp>
+#include <boost/test/unit_test.hpp>
+
+namespace mpl = boost::mpl;
+namespace proto = boost::proto;
+namespace fusion = boost::fusion;
+using proto::_;
+
+template<int I>
+struct placeholder
+{};
+
+namespace test1
+{
+//[ CalcGrammar
+ // This is the grammar for calculator expressions,
+ // to which we will attach transforms for computing
+ // the expressions' arity.
+ /*<< A Calculator expression is ... >>*/
+ struct CalcArity
+ : proto::or_<
+ /*<< _1, or ... >>*/
+ proto::terminal< placeholder<0> >
+ /*<< _2, or ... >>*/
+ , proto::terminal< placeholder<1> >
+ /*<< some other terminal, or ... >>*/
+ , proto::terminal< _ >
+ /*<< a unary expression where the operand is a calculator expression, or ... >>*/
+ , proto::unary_expr< _, CalcArity >
+ /*<< a binary expression where the operands are calculator expressions >>*/
+ , proto::binary_expr< _, CalcArity, CalcArity >
+ >
+ {};
+//]
+}
+
+//[ binary_arity
+/*<< The `CalculatorArity` is a transform for calculating
+the arity of a calculator expression. It will be define in
+terms of `binary_arity`, which is defined in terms of
+`CalculatorArity`; hence, the definition is recursive.>>*/
+struct CalculatorArity;
+
+// A custom transform that returns the arity of a unary
+// calculator expression by finding the arity of the
+// child expression.
+struct unary_arity
+ /*<< Custom transforms should inherit from
+ transform<>. In some cases, (e.g., when the transform
+ is a template), it is also necessary to specialize
+ the proto::is_callable<> trait. >>*/
+ : proto::transform<unary_arity>
+{
+ template<typename Expr, typename State, typename Data>
+ /*<< Transforms have a nested `impl<>` that is
+ a valid TR1 function object. >>*/
+ struct impl
+ : proto::transform_impl<Expr, State, Data>
+ {
+ /*<< Get the child. >>*/
+ typedef typename proto::result_of::child<Expr>::type child_expr;
+
+ /*<< Apply `CalculatorArity` to find the arity of the child. >>*/
+ typedef typename boost::result_of<CalculatorArity(child_expr, State, Data)>::type result_type;
+
+ /*<< The `unary_arity` transform doesn't have an interesting
+ runtime counterpart, so just return a default-constructed object
+ of the correct type. >>*/
+ result_type operator ()(proto::ignore, proto::ignore, proto::ignore) const
+ {
+ return result_type();
+ }
+ };
+};
+
+// A custom transform that returns the arity of a binary
+// calculator expression by finding the maximum of the
+// arities of the mpl::int_<2> child expressions.
+struct binary_arity
+ /*<< All custom transforms should inherit from
+ transform. In some cases, (e.g., when the transform
+ is a template), it is also necessary to specialize
+ the proto::is_callable<> trait. >>*/
+ : proto::transform<binary_arity>
+{
+ template<typename Expr, typename State, typename Data>
+ /*<< Transforms have a nested `impl<>` that is
+ a valid TR1 function object. >>*/
+ struct impl
+ : proto::transform_impl<Expr, State, Data>
+ {
+ /*<< Get the left and right children. >>*/
+ typedef typename proto::result_of::left<Expr>::type left_expr;
+ typedef typename proto::result_of::right<Expr>::type right_expr;
+
+ /*<< Apply `CalculatorArity` to find the arity of the left and right children. >>*/
+ typedef typename boost::result_of<CalculatorArity(left_expr, State, Data)>::type left_arity;
+ typedef typename boost::result_of<CalculatorArity(right_expr, State, Data)>::type right_arity;
+
+ /*<< The return type is the maximum of the children's arities. >>*/
+ typedef typename mpl::max<left_arity, right_arity>::type result_type;
+
+ /*<< The `unary_arity` transform doesn't have an interesting
+ runtime counterpart, so just return a default-constructed object
+ of the correct type. >>*/
+ result_type operator ()(proto::ignore, proto::ignore, proto::ignore) const
+ {
+ return result_type();
+ }
+ };
+};
+//]
+
+proto::terminal< placeholder<0> >::type const _1 = {};
+proto::terminal< placeholder<1> >::type const _2 = {};
+
+//[ CalculatorArityGrammar
+struct CalculatorArity
+ : proto::or_<
+ proto::when< proto::terminal< placeholder<0> >, mpl::int_<1>() >
+ , proto::when< proto::terminal< placeholder<1> >, mpl::int_<2>() >
+ , proto::when< proto::terminal<_>, mpl::int_<0>() >
+ , proto::when< proto::unary_expr<_, _>, unary_arity >
+ , proto::when< proto::binary_expr<_, _, _>, binary_arity >
+ >
+{};
+//]
+
+//[ CalcArity
+struct CalcArity
+ : proto::or_<
+ proto::when< proto::terminal< placeholder<0> >,
+ mpl::int_<1>()
+ >
+ , proto::when< proto::terminal< placeholder<1> >,
+ mpl::int_<2>()
+ >
+ , proto::when< proto::terminal<_>,
+ mpl::int_<0>()
+ >
+ , proto::when< proto::unary_expr<_, CalcArity>,
+ CalcArity(proto::_child)
+ >
+ , proto::when< proto::binary_expr<_, CalcArity, CalcArity>,
+ mpl::max<CalcArity(proto::_left),
+ CalcArity(proto::_right)>()
+ >
+ >
+{};
+//]
+
+// BUGBUG find workaround for this
+#if BOOST_WORKAROUND(BOOST_MSVC, == 1310)
+#define _pop_front(x) call<proto::_pop_front(x)>
+#define _value(x) call<proto::_value(x)>
+#endif
+
+//[ AsArgList
+// This transform matches function invocations such as foo(1,'a',"b")
+// and transforms them into Fusion cons lists of their arguments. In this
+// case, the result would be cons(1, cons('a', cons("b", nil()))).
+struct ArgsAsList
+ : proto::when<
+ proto::function<proto::terminal<_>, proto::vararg<proto::terminal<_> > >
+ /*<< Use a `fold<>` transform to iterate over the children of this
+ node in forward order, building a fusion list from front to back. >>*/
+ , proto::fold<
+ /*<< The first child expression of a `function<>` node is the
+ function being invoked. We don't want that in our list, so use
+ `pop_front()` to remove it. >>*/
+ proto::_pop_front(_)
+ /*<< `nil` is the initial state used by the `fold<>` transform. >>*/
+ , fusion::nil()
+ /*<< Put the rest of the function arguments in a fusion cons
+ list. >>*/
+ , proto::functional::push_back(proto::_state, proto::_value)
+ >
+ >
+{};
+//]
+
+//[ FoldTreeToList
+// This transform matches expressions of the form (_1=1,'a',"b")
+// (note the use of the comma operator) and transforms it into a
+// Fusion cons list of their arguments. In this case, the result
+// would be cons(1, cons('a', cons("b", nil()))).
+struct FoldTreeToList
+ : proto::or_<
+ // This grammar describes what counts as the terminals in expressions
+ // of the form (_1=1,'a',"b"), which will be flattened using
+ // reverse_fold_tree<> below.
+ proto::when< proto::assign<_, proto::terminal<_> >
+ , proto::_value(proto::_right)
+ >
+ , proto::when< proto::terminal<_>
+ , proto::_value
+ >
+ , proto::when<
+ proto::comma<FoldTreeToList, FoldTreeToList>
+ /*<< Fold all terminals that are separated by commas into a Fusion cons list. >>*/
+ , proto::reverse_fold_tree<
+ _
+ , fusion::nil()
+ , fusion::cons<FoldTreeToList, proto::_state>(FoldTreeToList, proto::_state)
+ >
+ >
+ >
+{};
+//]
+
+//[ Promote
+// This transform finds all float terminals in an expression and promotes
+// them to doubles.
+struct Promote
+ : proto::or_<
+ /*<< Match a `terminal<float>`, then construct a
+ `terminal<double>::type` with the `float`. >>*/
+ proto::when<proto::terminal<float>, proto::terminal<double>::type(proto::_value) >
+ , proto::when<proto::terminal<_> >
+ /*<< `nary_expr<>` has a pass-through transform which
+ will transform each child sub-expression using the
+ `Promote` transform. >>*/
+ , proto::when<proto::nary_expr<_, proto::vararg<Promote> > >
+ >
+{};
+//]
+
+//[ LazyMakePair
+struct make_pair_tag {};
+proto::terminal<make_pair_tag>::type const make_pair_ = {{}};
+
+// This transform matches lazy function invocations like
+// `make_pair_(1, 3.14)` and actually builds a `std::pair<>`
+// from the arguments.
+struct MakePair
+ : proto::when<
+ /*<< Match expressions like `make_pair_(1, 3.14)` >>*/
+ proto::function<
+ proto::terminal<make_pair_tag>
+ , proto::terminal<_>
+ , proto::terminal<_>
+ >
+ /*<< Return `std::pair<F,S>(f,s)` where `f` and `s` are the
+ first and second arguments to the lazy `make_pair_()` function.
+ (This uses `proto::make<>` under the covers to evaluate the
+ transform.)>>*/
+ , std::pair<
+ proto::_value(proto::_child1)
+ , proto::_value(proto::_child2)
+ >(
+ proto::_value(proto::_child1)
+ , proto::_value(proto::_child2)
+ )
+ >
+{};
+//]
+
+namespace lazy_make_pair2
+{
+ //[ LazyMakePair2
+ struct make_pair_tag {};
+ proto::terminal<make_pair_tag>::type const make_pair_ = {{}};
+
+ // Like std::make_pair(), only as a function object.
+ /*<<Inheriting from `proto::callable` lets Proto know
+ that this is a callable transform, so we can use it
+ without having to wrap it in `proto::call<>`.>>*/
+ struct make_pair : proto::callable
+ {
+ template<typename Sig> struct result;
+
+ template<typename This, typename First, typename Second>
+ struct result<This(First, Second)>
+ {
+ typedef
+ std::pair<
+ BOOST_PROTO_UNCVREF(First)
+ , BOOST_PROTO_UNCVREF(Second)
+ >
+ type;
+ };
+
+ template<typename First, typename Second>
+ std::pair<First, Second>
+ operator()(First const &first, Second const &second) const
+ {
+ return std::make_pair(first, second);
+ }
+ };
+
+ // This transform matches lazy function invocations like
+ // `make_pair_(1, 3.14)` and actually builds a `std::pair<>`
+ // from the arguments.
+ struct MakePair
+ : proto::when<
+ /*<< Match expressions like `make_pair_(1, 3.14)` >>*/
+ proto::function<
+ proto::terminal<make_pair_tag>
+ , proto::terminal<_>
+ , proto::terminal<_>
+ >
+ /*<< Return `make_pair()(f,s)` where `f` and `s` are the
+ first and second arguments to the lazy `make_pair_()` function.
+ (This uses `proto::call<>` under the covers to evaluate the
+ transform.)>>*/
+ , make_pair(
+ proto::_value(proto::_child1)
+ , proto::_value(proto::_child2)
+ )
+ >
+ {};
+ //]
+}
+
+
+//[ NegateInt
+struct NegateInt
+ : proto::when<proto::terminal<int>, proto::negate<_>(_)>
+{};
+//]
+
+#ifndef BOOST_MSVC
+//[ SquareAndPromoteInt
+struct SquareAndPromoteInt
+ : proto::when<
+ proto::terminal<int>
+ , proto::_make_multiplies(
+ proto::terminal<long>::type(proto::_value)
+ , proto::terminal<long>::type(proto::_value)
+ )
+ >
+{};
+//]
+#endif
+
+namespace lambda_transform
+{
+ //[LambdaTransform
+ template<typename N>
+ struct placeholder : N {};
+
+ // A function object that calls fusion::at()
+ struct at : proto::callable
+ {
+ template<typename Sig>
+ struct result;
+
+ template<typename This, typename Cont, typename Index>
+ struct result<This(Cont, Index)>
+ : fusion::result_of::at<
+ typename boost::remove_reference<Cont>::type
+ , typename boost::remove_reference<Index>::type
+ >
+ {};
+
+ template<typename Cont, typename Index>
+ typename fusion::result_of::at<Cont, Index>::type
+ operator ()(Cont &cont, Index const &) const
+ {
+ return fusion::at<Index>(cont);
+ }
+ };
+
+ // A transform that evaluates a lambda expression.
+ struct LambdaEval
+ : proto::or_<
+ /*<<When you match a placeholder ...>>*/
+ proto::when<
+ proto::terminal<placeholder<_> >
+ /*<<... call at() with the data parameter, which
+ is a tuple, and the placeholder, which is an MPL
+ Integral Constant.>>*/
+ , at(proto::_data, proto::_value)
+ >
+ /*<<Otherwise, use the _default<> transform, which
+ gives the operators their usual C++ meanings.>>*/
+ , proto::otherwise< proto::_default<LambdaEval> >
+ >
+ {};
+
+ // Define the lambda placeholders
+ proto::terminal<placeholder<mpl::int_<0> > >::type const _1 = {};
+ proto::terminal<placeholder<mpl::int_<1> > >::type const _2 = {};
+
+ void test_lambda()
+ {
+ // a tuple that contains the values
+ // of _1 and _2
+ fusion::tuple<int, int> tup(2,3);
+
+ // Use LambdaEval to evaluate a lambda expression
+ int j = LambdaEval()( _2 - _1, 0, tup );
+ BOOST_CHECK_EQUAL(j, 1);
+
+ // You can mutate leaves in an expression tree
+ proto::literal<int> k(42);
+ int &l = LambdaEval()( k += 4, 0, tup );
+ BOOST_CHECK_EQUAL(k.get(), 46);
+ BOOST_CHECK_EQUAL(&l, &k.get());
+
+ // You can mutate the values in the tuple, too.
+ LambdaEval()( _1 += 4, 0, tup );
+ BOOST_CHECK_EQUAL(6, fusion::at_c<0>(tup));
+ }
+ //]
+}
+
+void test_examples()
+{
+ //[ CalculatorArityTest
+ int i = 0; // not used, dummy state and data parameter
+
+ std::cout << CalculatorArity()( proto::lit(100) * 200, i, i) << '\n';
+ std::cout << CalculatorArity()( (_1 - _1) / _1 * 100, i, i) << '\n';
+ std::cout << CalculatorArity()( (_2 - _1) / _2 * 100, i, i) << '\n';
+ //]
+
+ BOOST_CHECK_EQUAL(0, CalculatorArity()( proto::lit(100) * 200, i, i));
+ BOOST_CHECK_EQUAL(1, CalculatorArity()( (_1 - _1) / _1 * 100, i, i));
+ BOOST_CHECK_EQUAL(2, CalculatorArity()( (_2 - _1) / _2 * 100, i, i));
+
+ BOOST_CHECK_EQUAL(0, CalcArity()( proto::lit(100) * 200, i, i));
+ BOOST_CHECK_EQUAL(1, CalcArity()( (_1 - _1) / _1 * 100, i, i));
+ BOOST_CHECK_EQUAL(2, CalcArity()( (_2 - _1) / _2 * 100, i, i));
+
+ using boost::fusion::cons;
+ using boost::fusion::nil;
+ cons<int, cons<char, cons<std::string> > > args(ArgsAsList()( _1(1, 'a', std::string("b")), i, i ));
+ BOOST_CHECK_EQUAL(args.car, 1);
+ BOOST_CHECK_EQUAL(args.cdr.car, 'a');
+ BOOST_CHECK_EQUAL(args.cdr.cdr.car, std::string("b"));
+
+ cons<int, cons<char, cons<std::string> > > lst(FoldTreeToList()( (_1 = 1, 'a', std::string("b")), i, i ));
+ BOOST_CHECK_EQUAL(lst.car, 1);
+ BOOST_CHECK_EQUAL(lst.cdr.car, 'a');
+ BOOST_CHECK_EQUAL(lst.cdr.cdr.car, std::string("b"));
+
+ proto::plus<
+ proto::terminal<double>::type
+ , proto::terminal<double>::type
+ >::type p = Promote()( proto::lit(1.f) + 2.f, i, i );
+
+ //[ LazyMakePairTest
+ int j = 0; // not used, dummy state and data parameter
+
+ std::pair<int, double> p2 = MakePair()( make_pair_(1, 3.14), j, j );
+
+ std::cout << p2.first << std::endl;
+ std::cout << p2.second << std::endl;
+ //]
+
+ BOOST_CHECK_EQUAL(p2.first, 1);
+ BOOST_CHECK_EQUAL(p2.second, 3.14);
+
+ std::pair<int, double> p3 = lazy_make_pair2::MakePair()( lazy_make_pair2::make_pair_(1, 3.14), j, j );
+
+ std::cout << p3.first << std::endl;
+ std::cout << p3.second << std::endl;
+
+ BOOST_CHECK_EQUAL(p3.first, 1);
+ BOOST_CHECK_EQUAL(p3.second, 3.14);
+
+ NegateInt()(proto::lit(1), i, i);
+ #ifndef BOOST_MSVC
+ SquareAndPromoteInt()(proto::lit(1), i, i);
+ #endif
+
+ lambda_transform::test_lambda();
+}
+
+using namespace boost::unit_test;
+///////////////////////////////////////////////////////////////////////////////
+// init_unit_test_suite
+//
+test_suite* init_unit_test_suite( int argc, char* argv[] )
+{
+ test_suite *test = BOOST_TEST_SUITE("test examples from the documentation");
+
+ test->add(BOOST_TEST_CASE(&test_examples));
+
+ return test;
+}