diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
commit | 483eb2f56657e8e7f419ab1a4fab8dce9ade8609 (patch) | |
tree | e5d88d25d870d5dedacb6bbdbe2a966086a0a5cf /src/boost/libs/proto | |
parent | Initial commit. (diff) | |
download | ceph-upstream.tar.xz ceph-upstream.zip |
Adding upstream version 14.2.21.upstream/14.2.21upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/boost/libs/proto')
47 files changed, 9336 insertions, 0 deletions
diff --git a/src/boost/libs/proto/example/Jamfile.v2 b/src/boost/libs/proto/example/Jamfile.v2 new file mode 100644 index 00000000..7528f9ee --- /dev/null +++ b/src/boost/libs/proto/example/Jamfile.v2 @@ -0,0 +1,87 @@ +# (C) Copyright 2004: 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) + +exe hello + : + hello.cpp + ; + + +exe calc1 + : + calc1.cpp + ; + +exe calc2 + : + calc2.cpp + ; + +exe calc3 + : + calc3.cpp + ; + +exe lazy_vector + : + lazy_vector.cpp + ; + +exe tarray + : + tarray.cpp + ; + +exe rgb + : + rgb.cpp + ; + +exe vec3 + : + vec3.cpp + ; + +exe vector + : + vector.cpp + ; + +exe mixed + : + mixed.cpp + ; + +exe futures + : + futures.cpp + ; + +exe map_assign + : + map_assign.cpp + ; + +exe mini_lambda + : + mini_lambda.cpp + ; + +exe virtual_member + : + virtual_member.cpp + ; + +exe external_transforms + : + external_transforms.cpp + ; + +exe lambda + : + lambda.cpp + : + <include>. + <toolset>clang:<cxxflags>-Wno-unused-local-typedef + ; diff --git a/src/boost/libs/proto/example/calc1.cpp b/src/boost/libs/proto/example/calc1.cpp new file mode 100644 index 00000000..d3fefa62 --- /dev/null +++ b/src/boost/libs/proto/example/calc1.cpp @@ -0,0 +1,68 @@ +//[ Calc1 +// 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) +// +// This is a simple example of how to build an arithmetic expression +// evaluator with placeholders. + +#include <iostream> +#include <boost/proto/core.hpp> +#include <boost/proto/context.hpp> +namespace proto = boost::proto; +using proto::_; + +template<int I> struct placeholder {}; + +// Define some placeholders +proto::terminal< placeholder< 1 > >::type const _1 = {{}}; +proto::terminal< placeholder< 2 > >::type const _2 = {{}}; + +// Define a calculator context, for evaluating arithmetic expressions +struct calculator_context + : proto::callable_context< calculator_context const > +{ + // The values bound to the placeholders + double d[2]; + + // The result of evaluating arithmetic expressions + typedef double result_type; + + explicit calculator_context(double d1 = 0., double d2 = 0.) + { + d[0] = d1; + d[1] = d2; + } + + // Handle the evaluation of the placeholder terminals + template<int I> + double operator ()(proto::tag::terminal, placeholder<I>) const + { + return d[ I - 1 ]; + } +}; + +template<typename Expr> +double evaluate( Expr const &expr, double d1 = 0., double d2 = 0. ) +{ + // Create a calculator context with d1 and d2 substituted for _1 and _2 + calculator_context const ctx(d1, d2); + + // Evaluate the calculator expression with the calculator_context + return proto::eval(expr, ctx); +} + +int main() +{ + // Displays "5" + std::cout << evaluate( _1 + 2.0, 3.0 ) << std::endl; + + // Displays "6" + std::cout << evaluate( _1 * _2, 3.0, 2.0 ) << std::endl; + + // Displays "0.5" + std::cout << evaluate( (_1 - _2) / _2, 3.0, 2.0 ) << std::endl; + + return 0; +} +//] diff --git a/src/boost/libs/proto/example/calc2.cpp b/src/boost/libs/proto/example/calc2.cpp new file mode 100644 index 00000000..6fc490bf --- /dev/null +++ b/src/boost/libs/proto/example/calc2.cpp @@ -0,0 +1,103 @@ +//[ Calc2 +// 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) +// +// This example enhances the simple arithmetic expression evaluator +// in calc1.cpp by using proto::extends to make arithmetic +// expressions immediately evaluable with operator (), a-la a +// function object + +#include <iostream> +#include <boost/proto/core.hpp> +#include <boost/proto/context.hpp> +namespace proto = boost::proto; +using proto::_; + +template<typename Expr> +struct calculator_expression; + +// Tell proto how to generate expressions in the calculator_domain +struct calculator_domain + : proto::domain<proto::generator<calculator_expression> > +{}; + +// Will be used to define the placeholders _1 and _2 +template<int I> struct placeholder {}; + +// Define a calculator context, for evaluating arithmetic expressions +// (This is as before, in calc1.cpp) +struct calculator_context + : proto::callable_context< calculator_context const > +{ + // The values bound to the placeholders + double d[2]; + + // The result of evaluating arithmetic expressions + typedef double result_type; + + explicit calculator_context(double d1 = 0., double d2 = 0.) + { + d[0] = d1; + d[1] = d2; + } + + // Handle the evaluation of the placeholder terminals + template<int I> + double operator ()(proto::tag::terminal, placeholder<I>) const + { + return d[ I - 1 ]; + } +}; + +// Wrap all calculator expressions in this type, which defines +// operator () to evaluate the expression. +template<typename Expr> +struct calculator_expression + : proto::extends<Expr, calculator_expression<Expr>, calculator_domain> +{ + explicit calculator_expression(Expr const &expr = Expr()) + : calculator_expression::proto_extends(expr) + {} + + BOOST_PROTO_EXTENDS_USING_ASSIGN(calculator_expression<Expr>) + + // Override operator () to evaluate the expression + double operator ()() const + { + calculator_context const ctx; + return proto::eval(*this, ctx); + } + + double operator ()(double d1) const + { + calculator_context const ctx(d1); + return proto::eval(*this, ctx); + } + + double operator ()(double d1, double d2) const + { + calculator_context const ctx(d1, d2); + return proto::eval(*this, ctx); + } +}; + +// Define some placeholders (notice they're wrapped in calculator_expression<>) +calculator_expression<proto::terminal< placeholder< 1 > >::type> const _1; +calculator_expression<proto::terminal< placeholder< 2 > >::type> const _2; + +// Now, our arithmetic expressions are immediately executable function objects: +int main() +{ + // Displays "5" + std::cout << (_1 + 2.0)( 3.0 ) << std::endl; + + // Displays "6" + std::cout << ( _1 * _2 )( 3.0, 2.0 ) << std::endl; + + // Displays "0.5" + std::cout << ( (_1 - _2) / _2 )( 3.0, 2.0 ) << std::endl; + + return 0; +} +//] diff --git a/src/boost/libs/proto/example/calc3.cpp b/src/boost/libs/proto/example/calc3.cpp new file mode 100644 index 00000000..9ca97d65 --- /dev/null +++ b/src/boost/libs/proto/example/calc3.cpp @@ -0,0 +1,154 @@ +//[ Calc3 +// 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) +// +// This example enhances the arithmetic expression evaluator +// in calc2.cpp by using a proto transform to calculate the +// number of arguments an expression requires and using a +// compile-time assert to guarantee that the right number of +// arguments are actually specified. + +#include <iostream> +#include <boost/mpl/int.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/mpl/min_max.hpp> +#include <boost/proto/core.hpp> +#include <boost/proto/context.hpp> +#include <boost/proto/transform.hpp> +namespace mpl = boost::mpl; +namespace proto = boost::proto; +using proto::_; + +// Will be used to define the placeholders _1 and _2 +template<typename I> struct placeholder : I {}; + +// This grammar basically says that a calculator expression is one of: +// - A placeholder terminal +// - Some other terminal +// - Some non-terminal whose children are calculator expressions +// In addition, it has transforms that say how to calculate the +// expression arity for each of the three cases. +struct CalculatorGrammar + : proto::or_< + + // placeholders have a non-zero arity ... + proto::when< proto::terminal< placeholder<_> >, proto::_value > + + // Any other terminals have arity 0 ... + , proto::when< proto::terminal<_>, mpl::int_<0>() > + + // For any non-terminals, find the arity of the children and + // take the maximum. This is recursive. + , proto::when< proto::nary_expr<_, proto::vararg<_> > + , proto::fold<_, mpl::int_<0>(), mpl::max<CalculatorGrammar, proto::_state>() > > + + > +{}; + +// Simple wrapper for calculating a calculator expression's arity. +// It specifies mpl::int_<0> as the initial state. The data, which +// is not used, is mpl::void_. +template<typename Expr> +struct calculator_arity + : boost::result_of<CalculatorGrammar(Expr)> +{}; + +template<typename Expr> +struct calculator_expression; + +// Tell proto how to generate expressions in the calculator_domain +struct calculator_domain + : proto::domain<proto::generator<calculator_expression> > +{}; + +// Define a calculator context, for evaluating arithmetic expressions +// (This is as before, in calc1.cpp and calc2.cpp) +struct calculator_context + : proto::callable_context< calculator_context const > +{ + // The values bound to the placeholders + double d[2]; + + // The result of evaluating arithmetic expressions + typedef double result_type; + + explicit calculator_context(double d1 = 0., double d2 = 0.) + { + d[0] = d1; + d[1] = d2; + } + + // Handle the evaluation of the placeholder terminals + template<typename I> + double operator ()(proto::tag::terminal, placeholder<I>) const + { + return d[ I() - 1 ]; + } +}; + +// Wrap all calculator expressions in this type, which defines +// operator () to evaluate the expression. +template<typename Expr> +struct calculator_expression + : proto::extends<Expr, calculator_expression<Expr>, calculator_domain> +{ + typedef + proto::extends<Expr, calculator_expression<Expr>, calculator_domain> + base_type; + + explicit calculator_expression(Expr const &expr = Expr()) + : base_type(expr) + {} + + BOOST_PROTO_EXTENDS_USING_ASSIGN(calculator_expression<Expr>) + + // Override operator () to evaluate the expression + double operator ()() const + { + // Assert that the expression has arity 0 + BOOST_MPL_ASSERT_RELATION(0, ==, calculator_arity<Expr>::type::value); + calculator_context const ctx; + return proto::eval(*this, ctx); + } + + double operator ()(double d1) const + { + // Assert that the expression has arity 1 + BOOST_MPL_ASSERT_RELATION(1, ==, calculator_arity<Expr>::type::value); + calculator_context const ctx(d1); + return proto::eval(*this, ctx); + } + + double operator ()(double d1, double d2) const + { + // Assert that the expression has arity 2 + BOOST_MPL_ASSERT_RELATION(2, ==, calculator_arity<Expr>::type::value); + calculator_context const ctx(d1, d2); + return proto::eval(*this, ctx); + } +}; + +// Define some placeholders (notice they're wrapped in calculator_expression<>) +calculator_expression<proto::terminal< placeholder< mpl::int_<1> > >::type> const _1; +calculator_expression<proto::terminal< placeholder< mpl::int_<2> > >::type> const _2; + +// Now, our arithmetic expressions are immediately executable function objects: +int main() +{ + // Displays "5" + std::cout << (_1 + 2.0)( 3.0 ) << std::endl; + + // Displays "6" + std::cout << ( _1 * _2 )( 3.0, 2.0 ) << std::endl; + + // Displays "0.5" + std::cout << ( (_1 - _2) / _2 )( 3.0, 2.0 ) << std::endl; + + // This won't compile because the arity of the + // expression doesn't match the number of arguments + // ( (_1 - _2) / _2 )( 3.0 ); + + return 0; +} +//] diff --git a/src/boost/libs/proto/example/external_transforms.cpp b/src/boost/libs/proto/example/external_transforms.cpp new file mode 100644 index 00000000..3667ebbd --- /dev/null +++ b/src/boost/libs/proto/example/external_transforms.cpp @@ -0,0 +1,128 @@ +//[ CheckedCalc +// Copyright 2011 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) +// +// This is an example of how to specify a transform externally so +// that a single grammar can be used to drive multiple differnt +// calculations. In particular, it defines a calculator grammar +// that computes the result of an expression with either checked +// or non-checked division. + +#include <iostream> +#include <boost/assert.hpp> +#include <boost/mpl/int.hpp> +#include <boost/mpl/next.hpp> +#include <boost/mpl/min_max.hpp> +#include <boost/fusion/container/vector.hpp> +#include <boost/fusion/container/generation/make_vector.hpp> +#include <boost/proto/proto.hpp> +namespace mpl = boost::mpl; +namespace proto = boost::proto; +namespace fusion = boost::fusion; + +// The argument placeholder type +template<typename I> struct placeholder : I {}; + +// Give each rule in the grammar a "name". This is so that we +// can easily dispatch on it later. +struct calc_grammar; +struct divides_rule : proto::divides<calc_grammar, calc_grammar> {}; + +// Use external transforms in calc_gramar +struct calc_grammar + : proto::or_< + proto::when< + proto::terminal<placeholder<proto::_> > + , proto::functional::at(proto::_state, proto::_value) + > + , proto::when< + proto::terminal<proto::convertible_to<double> > + , proto::_value + > + , proto::when< + proto::plus<calc_grammar, calc_grammar> + , proto::_default<calc_grammar> + > + , proto::when< + proto::minus<calc_grammar, calc_grammar> + , proto::_default<calc_grammar> + > + , proto::when< + proto::multiplies<calc_grammar, calc_grammar> + , proto::_default<calc_grammar> + > + // Note that we don't specify how division nodes are + // handled here. Proto::external_transform is a placeholder + // for an actual transform. + , proto::when< + divides_rule + , proto::external_transform + > + > +{}; + +template<typename E> struct calc_expr; +struct calc_domain : proto::domain<proto::generator<calc_expr> > {}; + +template<typename E> +struct calc_expr + : proto::extends<E, calc_expr<E>, calc_domain> +{ + calc_expr(E const &e = E()) : calc_expr::proto_extends(e) {} +}; + +calc_expr<proto::terminal<placeholder<mpl::int_<0> > >::type> _1; +calc_expr<proto::terminal<placeholder<mpl::int_<1> > >::type> _2; + +// Use proto::external_transforms to map from named grammar rules to +// transforms. +struct non_checked_division + : proto::external_transforms< + proto::when< divides_rule, proto::_default<calc_grammar> > + > +{}; + +struct division_by_zero : std::exception {}; + +struct do_checked_divide + : proto::callable +{ + typedef int result_type; + int operator()(int left, int right) const + { + if (right == 0) throw division_by_zero(); + return left / right; + } +}; + +// Use proto::external_transforms again, this time to map the divides_rule +// to a transforms that performs checked division. +struct checked_division + : proto::external_transforms< + proto::when< + divides_rule + , do_checked_divide(calc_grammar(proto::_left), calc_grammar(proto::_right)) + > + > +{}; + +int main() +{ + non_checked_division non_checked; + int result2 = calc_grammar()(_1 / _2, fusion::make_vector(6, 2), non_checked); + BOOST_ASSERT(result2 == 3); + + try + { + checked_division checked; + // This should throw + int result3 = calc_grammar()(_1 / _2, fusion::make_vector(6, 0), checked); + BOOST_ASSERT(false); // shouldn't get here! + } + catch(division_by_zero) + { + std::cout << "caught division by zero!\n"; + } +} +//] diff --git a/src/boost/libs/proto/example/futures.cpp b/src/boost/libs/proto/example/futures.cpp new file mode 100644 index 00000000..29e77d6e --- /dev/null +++ b/src/boost/libs/proto/example/futures.cpp @@ -0,0 +1,134 @@ +//[ FutureGroup +// 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) +// +// This is an example of using Proto transforms to implement +// Howard Hinnant's future group proposal. + +#include <boost/fusion/include/vector.hpp> +#include <boost/fusion/include/as_vector.hpp> +#include <boost/fusion/include/joint_view.hpp> +#include <boost/fusion/include/single_view.hpp> +#include <boost/proto/core.hpp> +#include <boost/proto/transform.hpp> +namespace mpl = boost::mpl; +namespace proto = boost::proto; +namespace fusion = boost::fusion; +using proto::_; + +template<class L,class R> +struct pick_left +{ + BOOST_MPL_ASSERT((boost::is_same<L, R>)); + typedef L type; +}; + +// Work-arounds for Microsoft Visual C++ 7.1 +#if BOOST_WORKAROUND(BOOST_MSVC, == 1310) +#define FutureGroup(x) proto::call<FutureGroup(x)> +#endif + +// Define the grammar of future group expression, as well as a +// transform to turn them into a Fusion sequence of the correct +// type. +struct FutureGroup + : proto::or_< + // terminals become a single-element Fusion sequence + proto::when< + proto::terminal<_> + , fusion::single_view<proto::_value>(proto::_value) + > + // (a && b) becomes a concatenation of the sequence + // from 'a' and the one from 'b': + , proto::when< + proto::logical_and<FutureGroup, FutureGroup> + , fusion::joint_view< + boost::add_const<FutureGroup(proto::_left) > + , boost::add_const<FutureGroup(proto::_right) > + >(FutureGroup(proto::_left), FutureGroup(proto::_right)) + > + // (a || b) becomes the sequence for 'a', so long + // as it is the same as the sequence for 'b'. + , proto::when< + proto::logical_or<FutureGroup, FutureGroup> + , pick_left< + FutureGroup(proto::_left) + , FutureGroup(proto::_right) + >(FutureGroup(proto::_left)) + > + > +{}; + +#if BOOST_WORKAROUND(BOOST_MSVC, == 1310) +#undef FutureGroup +#endif + +template<class E> +struct future_expr; + +struct future_dom + : proto::domain<proto::generator<future_expr>, FutureGroup> +{}; + +// Expressions in the future group domain have a .get() +// member function that (ostensibly) blocks for the futures +// to complete and returns the results in an appropriate +// tuple. +template<class E> +struct future_expr + : proto::extends<E, future_expr<E>, future_dom> +{ + explicit future_expr(E const &e) + : future_expr::proto_extends(e) + {} + + typename fusion::result_of::as_vector< + typename boost::result_of<FutureGroup(E)>::type + >::type + get() const + { + return fusion::as_vector(FutureGroup()(*this)); + } +}; + +// The future<> type has an even simpler .get() +// member function. +template<class T> +struct future + : future_expr<typename proto::terminal<T>::type> +{ + future(T const &t = T()) + : future::proto_derived_expr(future::proto_base_expr::make(t)) + {} + + T get() const + { + return proto::value(*this); + } +}; + +// TEST CASES +struct A {}; +struct B {}; +struct C {}; + +int main() +{ + using fusion::vector; + future<A> a; + future<B> b; + future<C> c; + future<vector<A,B> > ab; + + // Verify that various future groups have the + // correct return types. + A t0 = a.get(); + vector<A, B, C> t1 = (a && b && c).get(); + vector<A, C> t2 = ((a || a) && c).get(); + vector<A, B, C> t3 = ((a && b || a && b) && c).get(); + vector<vector<A, B>, C> t4 = ((ab || ab) && c).get(); + + return 0; +} +//] diff --git a/src/boost/libs/proto/example/hello.cpp b/src/boost/libs/proto/example/hello.cpp new file mode 100644 index 00000000..4b9cd99b --- /dev/null +++ b/src/boost/libs/proto/example/hello.cpp @@ -0,0 +1,28 @@ +//[ HelloWorld +//////////////////////////////////////////////////////////////////// +// 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/proto/core.hpp> +#include <boost/proto/context.hpp> +// This #include is only needed for compilers that use typeof emulation: +#include <boost/typeof/std/ostream.hpp> +namespace proto = boost::proto; + +proto::terminal< std::ostream & >::type cout_ = {std::cout}; + +template< typename Expr > +void evaluate( Expr const & expr ) +{ + proto::default_context ctx; + proto::eval(expr, ctx); +} + +int main() +{ + evaluate( cout_ << "hello" << ',' << " world" ); + return 0; +} +//] diff --git a/src/boost/libs/proto/example/lambda.cpp b/src/boost/libs/proto/example/lambda.cpp new file mode 100644 index 00000000..bb5c1f03 --- /dev/null +++ b/src/boost/libs/proto/example/lambda.cpp @@ -0,0 +1,17 @@ +//[ Lambda +/////////////////////////////////////////////////////////////////////////////// +// 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) +// +// This example builds a simple but functional lambda library using Proto. + +#include <iostream> +#include "./lambda.hpp" + +int main() +{ + using namespace boost::lambda; + int i = (_1 + _1)(42); + std::cout << i << std::endl; +} diff --git a/src/boost/libs/proto/example/lambda.hpp b/src/boost/libs/proto/example/lambda.hpp new file mode 100644 index 00000000..a08d9bf6 --- /dev/null +++ b/src/boost/libs/proto/example/lambda.hpp @@ -0,0 +1,1730 @@ +#ifndef BOOST_PP_IS_ITERATING + /////////////////////////////////////////////////////////////////////////////// + // 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) + // + // This example contains a full-featured reimplementation of the old, + // now-deprecated Boost Lambda Library (BLL) on top of Boost.Proto. It + // is necessarily complex to accomodate all the quirks and inconsistencies + // of that old library, but it is a good example of how to build a + // complete and full-featured EDLS using Proto. + #ifndef BOOST_LAMBDA_HPP_EAN_04_19_2008 + #define BOOST_LAMBDA_HPP_EAN_04_19_2008 + + #include <iosfwd> + #include <typeinfo> + #include <algorithm> + #include <boost/ref.hpp> + #include <boost/assert.hpp> + #include <boost/mpl/or.hpp> + #include <boost/mpl/int.hpp> + #include <boost/mpl/void.hpp> + #include <boost/mpl/identity.hpp> + #include <boost/mpl/next_prior.hpp> + #include <boost/mpl/min_max.hpp> + #include <boost/mpl/assert.hpp> + #include <boost/preprocessor.hpp> + #include <boost/utility/enable_if.hpp> + #include <boost/utility/result_of.hpp> + #include <boost/fusion/include/vector.hpp> + #include <boost/type_traits/add_reference.hpp> + #include <boost/type_traits/remove_reference.hpp> + #include <boost/type_traits/remove_const.hpp> + #include <boost/type_traits/is_same.hpp> + #include <boost/proto/proto.hpp> + + #ifndef BOOST_LAMBDA_MAX_ARITY + # define BOOST_LAMBDA_MAX_ARITY 3 + #endif + + #ifdef _MSC_VER + # pragma warning(push) + # pragma warning(disable: 4355) // 'this' : used in base member initializer list + # pragma warning(disable: 4065) // switch statement contains 'default' but no 'case' labels + #endif + + namespace boost { namespace lambda + { + namespace tag + { + struct if_ {}; + struct if_else_ {}; + struct for_ {}; + struct while_ {}; + struct do_while_ {}; + struct protect {}; + struct try_ {}; + struct throw_ {}; + struct rethrow_ {}; + struct switch_ {}; + struct default_ {}; + template<int I> struct case_ { static const int value = I; }; + template<typename E> struct catch_ { typedef E exception_type; }; + struct catch_all_ { typedef catch_all_ exception_type; }; + }; + + template<typename Int> + struct placeholder + { + typedef typename Int::tag tag; + typedef typename Int::value_type value_type; + typedef placeholder<Int> type; + typedef placeholder<typename Int::next> next; + typedef placeholder<typename Int::prior> prior; + static const value_type value = Int::value; + + friend std::ostream &operator<<(std::ostream &sout, placeholder) + { + return sout << "boost::lambda::_" << (Int::value+1); + } + }; + + struct exception_placeholder + {}; + + struct no_exception_type {}; + no_exception_type const no_exception = {}; + + // Calculate the arity of a lambda expression + struct Arity + : proto::or_< + proto::when<proto::terminal<placeholder<proto::_> >, mpl::next<proto::_value>()> + , proto::when<proto::terminal<proto::_>, mpl::int_<0>()> + , proto::otherwise<proto::fold<proto::_, mpl::int_<0>(), mpl::max<proto::_state, Arity>()> > + > + {}; + + // True when a lambda expression can be applied with no arguments and + // without an active exception object + struct IsNullary + : proto::or_< + proto::when<proto::terminal<placeholder<proto::_> >, mpl::false_()> + , proto::when<proto::terminal<exception_placeholder>, mpl::false_()> + , proto::when<proto::terminal<proto::_>, mpl::true_()> + , proto::otherwise<proto::fold<proto::_, mpl::true_(), mpl::and_<proto::_state, IsNullary>()> > + > + {}; + + struct Eval; + + template<typename Expr, typename State, typename Data> + typename boost::result_of<Eval(Expr&, State&, Data&)>::type + eval_lambda(Expr& e, State& s, Data& d); + + struct EvalWhile : proto::transform<EvalWhile> + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef mpl::void_ result_type; + + result_type operator()( + typename impl::expr_param expr + , typename impl::state_param state + , typename impl::data_param data + ) const + { + while(eval_lambda(proto::left(expr), state, data)) + { + eval_lambda(proto::right(expr), state, data); + } + return result_type(); + } + }; + }; + + struct EvalDoWhile : proto::transform<EvalDoWhile> + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef mpl::void_ result_type; + + result_type operator()( + typename impl::expr_param expr + , typename impl::state_param state + , typename impl::data_param data + ) const + { + do + { + eval_lambda(proto::child_c<0>(expr), state, data); + } + while(eval_lambda(proto::child_c<1>(expr), state, data)); + + return result_type(); + } + }; + }; + + struct EvalFor : proto::transform<EvalFor> + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef mpl::void_ result_type; + + result_type operator()( + typename impl::expr_param expr + , typename impl::state_param state + , typename impl::data_param data + ) const + { + for(eval_lambda(proto::child_c<0>(expr), state, data) + ; eval_lambda(proto::child_c<1>(expr), state, data) + ; eval_lambda(proto::child_c<2>(expr), state, data)) + { + eval_lambda(proto::child_c<3>(expr), state, data); + } + return result_type(); + } + }; + }; + + struct EvalIf : proto::transform<EvalIf> + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef mpl::void_ result_type; + + result_type operator()( + typename impl::expr_param expr + , typename impl::state_param state + , typename impl::data_param data + ) const + { + if(eval_lambda(proto::left(expr), state, data)) + { + eval_lambda(proto::right(expr), state, data); + } + return result_type(); + } + }; + }; + + struct EvalIfElse : proto::transform<EvalIfElse> + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef mpl::void_ result_type; + + result_type operator()( + typename impl::expr_param expr + , typename impl::state_param state + , typename impl::data_param data + ) const + { + if(eval_lambda(proto::child_c<0>(expr), state, data)) + { + eval_lambda(proto::child_c<1>(expr), state, data); + } + else + { + eval_lambda(proto::child_c<2>(expr), state, data); + } + return result_type(); + } + }; + }; + + struct EvalException : proto::transform<EvalException> + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef typename remove_const<typename impl::state>::type result_type; + BOOST_MPL_ASSERT_NOT((is_same<result_type, no_exception_type>)); + BOOST_MPL_ASSERT_NOT((is_same<result_type, tag::catch_all_>)); + + typename impl::state_param operator()( + typename impl::expr_param + , typename impl::state_param state + , typename impl::data_param + ) const + { + return state; + } + }; + }; + + struct EvalSwitch : proto::transform<EvalSwitch> + { + template<typename Expr, typename State, typename Data, long Arity, typename BackTag> + struct impl2; + + #define M0(Z, N, DATA) \ + case proto::tag_of<typename proto::result_of::child_c<Expr, N>::type>::type::value: \ + eval_lambda(proto::child_c<N>(expr), state, data); \ + break; \ + /**/ + + #define M1(Z, N, DATA) \ + template<typename Expr, typename State, typename Data, typename BackTag> \ + struct impl2<Expr, State, Data, N, BackTag> \ + : proto::transform_impl<Expr, State, Data> \ + { \ + typedef void result_type; \ + \ + void operator()( \ + typename impl2::expr_param expr \ + , typename impl2::state_param state \ + , typename impl2::data_param data \ + ) const \ + { \ + switch(eval_lambda(proto::child_c<0>(expr), state, data)) \ + { \ + BOOST_PP_REPEAT_FROM_TO_ ## Z(1, N, M0, ~) \ + default: \ + break; \ + } \ + } \ + }; \ + \ + template<typename Expr, typename State, typename Data> \ + struct impl2<Expr, State, Data, N, tag::default_> \ + : proto::transform_impl<Expr, State, Data> \ + { \ + typedef void result_type; \ + \ + void operator()( \ + typename impl2::expr_param expr \ + , typename impl2::state_param state \ + , typename impl2::data_param data \ + ) const \ + { \ + switch(eval_lambda(proto::child_c<0>(expr), state, data)) \ + { \ + BOOST_PP_REPEAT_FROM_TO_ ## Z(1, BOOST_PP_DEC(N), M0, ~) \ + default:; \ + eval_lambda(proto::child_c<BOOST_PP_DEC(N)>(expr), state, data); \ + break; \ + } \ + } \ + }; \ + /**/ + BOOST_PP_REPEAT_FROM_TO(2, BOOST_PP_INC(BOOST_PROTO_MAX_ARITY), M1, ~) + #undef M0 + #undef M1 + + template<typename Expr, typename State, typename Data> + struct impl + : impl2< + Expr + , State + , Data + , proto::arity_of<Expr>::value + , typename proto::tag_of< + typename proto::result_of::child_c< + Expr + , proto::arity_of<Expr>::value-1 + >::type + >::type + > + {}; + }; + + struct throw_fun + { + BOOST_PROTO_CALLABLE() + typedef void result_type; + template<typename Expr> + void operator()(Expr const &e) const + { + throw e; + } + }; + + struct unwrap_ref : proto::callable + { + template<typename Sig> + struct result; + + template<typename This, typename T> + struct result<This(reference_wrapper<T>)> + { + typedef T &type; + }; + + template<typename This, typename T> + struct result<This(T &)> + : result<This(T)> + {}; + + template<typename T> + T &operator()(reference_wrapper<T> const &ref) const + { + return ref; + } + }; + + struct anytype + { + template<typename T> + anytype(T &) { BOOST_ASSERT(false); } + template<typename T> + operator T &() const { BOOST_ASSERT(false); throw; } + private: + anytype(); + }; + + struct rethrow_fun + { + BOOST_PROTO_CALLABLE() + typedef anytype result_type; + template<typename State> + anytype operator()(State const &) const + { + BOOST_MPL_ASSERT_NOT((is_same<State, no_exception_type>)); + throw; + } + }; + + struct Cases + { + template<typename Tag> + struct case_ + : proto::otherwise<proto::_default<Eval> > + {}; + + template<typename E> + struct case_<tag::catch_<E> > + : proto::otherwise<Eval(proto::_child)> + {}; + + template<int I> + struct case_<tag::case_<I> > + : proto::otherwise<Eval(proto::_child)> + {}; + }; + + template<> struct Cases::case_<tag::while_> : proto::otherwise<EvalWhile> {}; + template<> struct Cases::case_<tag::for_> : proto::otherwise<EvalFor> {}; + template<> struct Cases::case_<tag::if_> : proto::otherwise<EvalIf> {}; + template<> struct Cases::case_<tag::if_else_> : proto::otherwise<EvalIfElse> {}; + template<> struct Cases::case_<tag::do_while_> : proto::otherwise<EvalDoWhile> {}; + template<> struct Cases::case_<tag::switch_> : proto::otherwise<EvalSwitch> {}; + template<> struct Cases::case_<tag::protect> : proto::otherwise<proto::_child> {}; + template<> struct Cases::case_<tag::default_> : proto::otherwise<Eval(proto::_child)> {}; + template<> struct Cases::case_<tag::catch_all_> : proto::otherwise<Eval(proto::_child)> {}; + + template<> + struct Cases::case_<proto::tag::terminal> + : proto::or_< + proto::when< + proto::terminal<placeholder<proto::_> > + , proto::functional::at(proto::_data, proto::_value) + > + , proto::when< + proto::terminal<exception_placeholder> + , EvalException + > + , proto::when< + proto::terminal<reference_wrapper<proto::_> > + , unwrap_ref(proto::_value) + > + , proto::otherwise<proto::_default<Eval> > + > + {}; + + template<> + struct Cases::case_<proto::tag::function> + : proto::or_< + proto::when< + proto::function<proto::terminal<rethrow_fun> > + , rethrow_fun(proto::_state) + > + , proto::otherwise<proto::_default<Eval> > + > + {}; + + struct Eval + : proto::switch_<Cases> + {}; + + template<typename Expr, typename State, typename Data> + typename boost::result_of<Eval(Expr&, State&, Data&)>::type + eval_lambda(Expr& e, State& s, Data& d) + { + return Eval()(e, s, d); + } + + // Use a grammar to disable Proto's assignment operator overloads. + // We'll define our own because we want (x+=_1) to store x by + // reference. (In all other cases, variables are stored by value + // within lambda expressions.) + struct Grammar + : proto::switch_<struct AssignOps> + {}; + + struct AssignOps + { + template<typename Tag> struct case_ : proto::_ {}; + }; + + template<> struct AssignOps::case_<proto::tag::shift_left_assign> : proto::not_<proto::_> {}; + template<> struct AssignOps::case_<proto::tag::shift_right_assign> : proto::not_<proto::_> {}; + template<> struct AssignOps::case_<proto::tag::multiplies_assign> : proto::not_<proto::_> {}; + template<> struct AssignOps::case_<proto::tag::divides_assign> : proto::not_<proto::_> {}; + template<> struct AssignOps::case_<proto::tag::modulus_assign> : proto::not_<proto::_> {}; + template<> struct AssignOps::case_<proto::tag::plus_assign> : proto::not_<proto::_> {}; + template<> struct AssignOps::case_<proto::tag::minus_assign> : proto::not_<proto::_> {}; + template<> struct AssignOps::case_<proto::tag::bitwise_and_assign> : proto::not_<proto::_> {}; + template<> struct AssignOps::case_<proto::tag::bitwise_or_assign> : proto::not_<proto::_> {}; + template<> struct AssignOps::case_<proto::tag::bitwise_xor_assign> : proto::not_<proto::_> {}; + + template<typename Expr> + struct llexpr; + + // Wrap expressions in lambda::llexpr<>. + struct Generator + : proto::pod_generator<llexpr> + {}; + + // The domain for the lambda library. + struct lldomain + : proto::domain<Generator, Grammar, proto::default_domain> + { + // Make all terminals and children held by value instead of by reference. + // Proto::domain<>::as_expr<> holds everything it can by value; the only + // exceptions are function types, abstract types, and iostreams. + template<typename T> + struct as_child + : proto_base_domain::as_expr<T> + {}; + + // The exception is arrays, which should still be held by reference + template<typename T, std::size_t N> + struct as_child<T[N]> + : proto_base_domain::as_child<T[N]> + {}; + }; + + template<typename Sig> + struct llresult; + + template<typename This> + struct llresult<This()> + : mpl::if_c< + result_of<IsNullary(This &)>::type::value + , result_of<Eval(This &, no_exception_type const &, fusion::vector0<> &)> + , mpl::identity<void> + >::type + {}; + + #define M0(Z, N, DATA) \ + template<typename This BOOST_PP_ENUM_TRAILING_PARAMS_Z(Z, N, typename A)> \ + struct llresult<This(BOOST_PP_ENUM_PARAMS_Z(Z, N, A))> \ + : result_of< \ + Eval( \ + This & \ + , no_exception_type const & \ + , BOOST_PP_CAT(fusion::vector, N)<BOOST_PP_ENUM_PARAMS_Z(Z, N, A)> & \ + ) \ + > \ + {}; \ + /**/ + BOOST_PP_REPEAT_FROM_TO(1, BOOST_PP_INC(BOOST_LAMBDA_MAX_ARITY), M0, ~) + #undef M0 + + template<typename Expr> + struct llexpr + { + BOOST_PROTO_BASIC_EXTENDS(Expr, llexpr<Expr>, lldomain) + BOOST_PROTO_EXTENDS_ASSIGN() + BOOST_PROTO_EXTENDS_SUBSCRIPT() + + template<typename Sig> + struct result + : llresult<Sig> + {}; + + typename result<llexpr const()>::type + operator()() const + { + fusion::vector0<> args; + return eval_lambda(*this, no_exception, args); + } + + #define M1(Z, N, _) ((0)(1)) + + #define M2(R, PRODUCT) M3(R, BOOST_PP_SEQ_SIZE(PRODUCT), PRODUCT) + + #define M3(R, SIZE, PRODUCT) \ + template<BOOST_PP_ENUM_PARAMS(SIZE, typename A)> \ + typename result<llexpr const(BOOST_PP_SEQ_FOR_EACH_I_R(R, M5, ~, PRODUCT))>::type \ + operator ()(BOOST_PP_SEQ_FOR_EACH_I_R(R, M4, ~, PRODUCT)) const \ + { \ + BOOST_MPL_ASSERT_RELATION(result_of<Arity(Expr const &)>::type::value, <=, SIZE); \ + BOOST_PP_CAT(fusion::vector, SIZE)<BOOST_PP_SEQ_FOR_EACH_I_R(R, M5, ~, PRODUCT)> args \ + (BOOST_PP_SEQ_FOR_EACH_I_R(R, M6, ~, PRODUCT)); \ + return eval_lambda(*this, no_exception, args); \ + } \ + /**/ + + #define M4(R, _, I, ELEM) \ + BOOST_PP_COMMA_IF(I) BOOST_PP_CAT(A, I) BOOST_PP_CAT(C, ELEM) &BOOST_PP_CAT(a, I) \ + /**/ + + #define M5(R, _, I, ELEM) \ + BOOST_PP_COMMA_IF(I) BOOST_PP_CAT(A, I) BOOST_PP_CAT(C, ELEM)& \ + /**/ + + #define M6(R, _, I, ELEM) \ + BOOST_PP_COMMA_IF(I) BOOST_PP_CAT(a, I) \ + /**/ + + #define C0 + + #define C1 const + + #define BOOST_PP_ITERATION_PARAMS_1 (3, (1, BOOST_LAMBDA_MAX_ARITY, "lambda.hpp")) + #include BOOST_PP_ITERATE() + + #undef C0 + #undef C1 + #undef M1 + #undef M2 + #undef M3 + #undef M4 + #undef M5 + #undef M6 + }; + + typedef llexpr<proto::terminal<placeholder<mpl::int_<0> > >::type> placeholder1_type; + typedef llexpr<proto::terminal<placeholder<mpl::int_<1> > >::type> placeholder2_type; + typedef llexpr<proto::terminal<placeholder<mpl::int_<2> > >::type> placeholder3_type; + + placeholder1_type const _1 = {{{}}}; + placeholder2_type const _2 = {{{}}}; + placeholder3_type const _3 = {{{}}}; + + placeholder1_type const free1 = {{{}}}; + placeholder2_type const free2 = {{{}}}; + placeholder3_type const free3 = {{{}}}; + + typedef llexpr<proto::terminal<exception_placeholder>::type> placeholderE_type; + placeholderE_type const _e = {{{}}}; + + struct byref + { + template<typename Sig> + struct result; + + template<typename This, typename T> + struct result<This(T &)> + { + typedef llexpr<typename proto::terminal<T &>::type> type; + }; + + template<typename This, typename T> + struct result<This(llexpr<T> &)> + { + typedef boost::reference_wrapper<llexpr<T> > type; + }; + + template<typename This, typename T> + struct result<This(llexpr<T> const &)> + { + typedef boost::reference_wrapper<llexpr<T> const> type; + }; + + template<typename T> + typename result<byref(T &)>::type operator()(T &t) const + { + typename result<byref(T &)>::type that = {{t}}; + return that; + } + + template<typename T> + typename result<byref(T const &)>::type operator()(T const &t) const + { + typename result<byref(T const &)>::type that = {{t}}; + return that; + } + + template<typename T> + boost::reference_wrapper<llexpr<T> > operator()(llexpr<T> &t) const + { + return boost::ref(t); + } + + template<typename T> + boost::reference_wrapper<llexpr<T> const> operator()(llexpr<T> const &t) const + { + return boost::ref(t); + } + }; + + namespace exprns_ + { + // Ugh, the assign operators (and only the assign operators) store + // their left terminals by reference. That requires this special handling. + #define BOOST_LAMBDA_DEFINE_ASSIGN_OP(OP, TAG) \ + template<typename T, typename U> \ + typename proto::result_of::make_expr< \ + TAG \ + , lldomain \ + , typename boost::result_of<byref(T &)>::type \ + , U & \ + >::type const \ + operator OP(T &t, U &u) \ + { \ + return proto::make_expr<TAG, lldomain>(byref()(t), boost::ref(u)); \ + } \ + template<typename T, typename U> \ + typename proto::result_of::make_expr< \ + TAG \ + , lldomain \ + , typename boost::result_of<byref(T &)>::type \ + , U const & \ + >::type const \ + operator OP(T &t, U const &u) \ + { \ + return proto::make_expr<TAG, lldomain>(byref()(t), boost::ref(u)); \ + } \ + /**/ + + BOOST_LAMBDA_DEFINE_ASSIGN_OP(<<=, boost::proto::tag::shift_left_assign) + BOOST_LAMBDA_DEFINE_ASSIGN_OP(>>=, boost::proto::tag::shift_right_assign) + BOOST_LAMBDA_DEFINE_ASSIGN_OP(*= , boost::proto::tag::multiplies_assign) + BOOST_LAMBDA_DEFINE_ASSIGN_OP(/= , boost::proto::tag::divides_assign) + BOOST_LAMBDA_DEFINE_ASSIGN_OP(%= , boost::proto::tag::modulus_assign) + BOOST_LAMBDA_DEFINE_ASSIGN_OP(+= , boost::proto::tag::plus_assign) + BOOST_LAMBDA_DEFINE_ASSIGN_OP(-= , boost::proto::tag::minus_assign) + BOOST_LAMBDA_DEFINE_ASSIGN_OP(&= , boost::proto::tag::bitwise_and_assign) + BOOST_LAMBDA_DEFINE_ASSIGN_OP(|= , boost::proto::tag::bitwise_or_assign) + BOOST_LAMBDA_DEFINE_ASSIGN_OP(^= , boost::proto::tag::bitwise_xor_assign) + } + + template<typename T> + struct var_type + { + typedef llexpr<typename proto::terminal<T &>::type> type; + }; + + template<typename T> + llexpr<typename proto::terminal<T &>::type> const + var(T &t) + { + llexpr<typename proto::terminal<T &>::type> that = {{t}}; + return that; + } + + template<typename T> + struct constant_type + : proto::result_of::make_expr< + proto::tag::terminal + , lldomain + , T const & + > + {}; + + template<typename T> + typename constant_type<T>::type const + constant(T const &t) + { + typename constant_type<T>::type that = {{t}}; + return that; + } + + template<typename T> + struct constant_ref_type + { + typedef llexpr<typename proto::terminal<T const &>::type> type; + }; + + template<typename T> + llexpr<typename proto::terminal<T const &>::type> const + constant_ref(T const &t) + { + llexpr<typename proto::terminal<T const &>::type> that = {{t}}; + return that; + } + + template<typename Cond> + struct while_generator + { + explicit while_generator(Cond const &c) + : cond(c) + {} + + template<typename Body> + typename proto::result_of::make_expr< + tag::while_ + , lldomain + , Cond const & + , Body const & + >::type const + operator[](Body const &body) const + { + return proto::make_expr<tag::while_, lldomain>( + boost::ref(this->cond) + , boost::ref(body) + ); + } + + private: + Cond const &cond; + }; + + template<typename Expr> + while_generator<Expr> while_(Expr const &expr) + { + return while_generator<Expr>(expr); + } + + template<typename Expr> + struct else_generator + { + typedef typename proto::result_of::left<Expr const &>::type condition_type; + typedef typename proto::result_of::right<Expr const &>::type body1_type; + + explicit else_generator(Expr const &expr) + : if_(expr) + {} + + template<typename Body2> + typename proto::result_of::make_expr< + tag::if_else_ + , lldomain + , condition_type + , body1_type + , Body2 const & + >::type const + operator[](Body2 const &body2) const + { + return proto::make_expr<tag::if_else_, lldomain>( + boost::ref(proto::left(this->if_)) + , boost::ref(proto::right(this->if_)) + , boost::ref(body2) + ); + } + + private: + Expr const &if_; + }; + + template<typename Expr> + struct with_else : Expr + { + template<typename T> + with_else(T const &expr) + : Expr(expr) + , else_(*this) + {} + + else_generator<Expr> else_; + }; + + template<typename Cond> + struct if_generator + { + explicit if_generator(Cond const &c) + : cond(c) + {} + + template<typename Body> + with_else< + typename proto::result_of::make_expr< + tag::if_ + , lldomain + , Cond const & + , Body const & + >::type + > const + operator[](Body const &body) const + { + return proto::make_expr<tag::if_, lldomain>( + boost::ref(this->cond) + , boost::ref(body) + ); + } + + private: + Cond const &cond; + }; + + template<typename Expr> + if_generator<Expr> if_(Expr const &expr) + { + return if_generator<Expr>(expr); + } + + template<typename Init, typename Cond, typename Oper> + struct for_generator + { + explicit for_generator(Init const &i, Cond const &c, Oper const &o) + : init(i) + , cond(c) + , oper(o) + {} + + template<typename Body> + typename proto::result_of::make_expr< + tag::for_ + , lldomain + , Init const & + , Cond const & + , Oper const & + , Body const & + >::type const + operator[](Body const &body) const + { + return proto::make_expr<tag::for_, lldomain>( + boost::ref(this->init) + , boost::ref(this->cond) + , boost::ref(this->oper) + , boost::ref(body) + ); + } + + private: + Init const &init; + Cond const &cond; + Oper const &oper; + }; + + template<typename Init, typename Cond, typename Oper> + for_generator<Init, Cond, Oper> for_(Init const &i, Cond const &c, Oper const &o) + { + return for_generator<Init, Cond, Oper>(i, c, o); + } + + template<typename Body> + struct do_while_generator + { + explicit do_while_generator(Body const &b) + : body(b) + {} + + template<typename Cond> + typename proto::result_of::make_expr< + tag::do_while_ + , lldomain + , Body const & + , Cond const & + >::type const + operator()(Cond const &cond) const + { + return proto::make_expr<tag::do_while_, lldomain>( + boost::ref(this->body) + , boost::ref(cond) + ); + } + + private: + Body const &body; + }; + + template<typename Body> + struct do_body + { + explicit do_body(Body const &body) + : while_(body) + {} + + do_while_generator<Body> while_; + }; + + struct do_generator + { + template<typename Body> + do_body<Body> operator[](Body const &body) const + { + return do_body<Body>(body); + } + }; + + do_generator const do_ = {}; + + struct noop_fun + { + typedef void result_type; + void operator()() const {} + }; + + typedef llexpr<proto::function<llexpr<proto::terminal<noop_fun>::type> >::type> noop_type; + noop_type const noop = {{{{{}}}}}; + + template<typename Init, typename Cond, typename Oper> + typename proto::result_of::make_expr< + tag::for_ + , lldomain + , Init const & + , Cond const & + , Oper const & + , noop_type const & + >::type const + for_loop(Init const &init, Cond const &cond, Oper const &oper) + { + return proto::make_expr<tag::for_, lldomain>( + boost::ref(init) + , boost::ref(cond) + , boost::ref(oper) + , boost::ref(noop) + ); + } + + template<typename Init, typename Cond, typename Oper, typename Body> + typename proto::result_of::make_expr< + tag::for_ + , lldomain + , Init const & + , Cond const & + , Oper const & + , Body const & + >::type const + for_loop(Init const &init, Cond const &cond, Oper const &oper, Body const &body) + { + return proto::make_expr<tag::for_>( + boost::ref(init) + , boost::ref(cond) + , boost::ref(oper) + , boost::ref(body) + ); + } + + template<typename Cond, typename Body> + typename proto::result_of::make_expr< + tag::while_ + , lldomain + , Cond const & + , Body const & + >::type const + while_loop(Cond const &cond, Body const &body) + { + return proto::make_expr<tag::while_, lldomain>( + boost::ref(cond) + , boost::ref(body) + ); + } + + template<typename Cond> + typename proto::result_of::make_expr< + tag::while_ + , lldomain + , Cond const & + , noop_type const & + >::type const + while_loop(Cond const &cond) + { + return proto::make_expr<tag::while_, lldomain>( + boost::ref(cond) + , boost::ref(noop) + ); + } + + template<typename Cond, typename Body> + typename proto::result_of::make_expr< + tag::do_while_ + , lldomain + , Body const & + , Cond const & + >::type const + do_while_loop(Cond const &cond, Body const &body) + { + return proto::make_expr<tag::do_while_, lldomain>( + boost::ref(body) + , boost::ref(cond) + ); + } + + template<typename Cond> + typename proto::result_of::make_expr< + tag::do_while_ + , lldomain + , noop_type const & + , Cond const & + >::type const + do_while_loop(Cond const &cond) + { + return proto::make_expr<tag::do_while_, lldomain>( + boost::ref(noop) + , boost::ref(cond) + ); + } + + template<typename Cond, typename Body1> + typename proto::result_of::make_expr< + tag::if_ + , lldomain + , Cond const & + , Body1 const & + >::type const + if_then(Cond const &cond, Body1 const &body1) + { + return proto::make_expr<tag::if_, lldomain>( + boost::ref(cond) + , boost::ref(body1) + ); + } + + template<typename Cond, typename Body1, typename Body2> + typename proto::result_of::make_expr< + tag::if_else_ + , lldomain + , Cond const & + , Body1 const & + , Body2 const & + >::type const + if_then_else(Cond const &cond, Body1 const &body1, Body2 const &body2) + { + return proto::make_expr<tag::if_else_, lldomain>( + boost::ref(cond) + , boost::ref(body1) + , boost::ref(body2) + ); + } + + template<typename Cond, typename Body1, typename Body2> + typename proto::result_of::make_expr< + proto::tag::if_else_ + , lldomain + , Cond const & + , Body1 const & + , Body2 const & + >::type const + if_then_else_return(Cond const &cond, Body1 const &body1, Body2 const &body2) + { + return proto::make_expr<proto::tag::if_else_, lldomain>( + boost::ref(cond) + , boost::ref(body1) + , boost::ref(body2) + ); + } + + template<typename T> + T const &make_const(T const &t) + { + return t; + } + + #define M1(N, typename_A, A_const_ref, A_const_ref_a, ref_a) \ + template<typename_A(N)> \ + typename proto::result_of::make_expr< \ + proto::tag::function \ + , lldomain \ + , A_const_ref(N) \ + >::type const \ + bind(A_const_ref_a(N)) \ + { \ + return proto::make_expr<proto::tag::function, lldomain>(ref_a(N)); \ + } \ + \ + template<typename Ret, typename_A(N)> \ + typename proto::result_of::make_expr< \ + proto::tag::function \ + , lldomain \ + , A_const_ref(N) \ + >::type const \ + bind(A_const_ref_a(N)) \ + { \ + return proto::make_expr<proto::tag::function, lldomain>(ref_a(N)); \ + } \ + /**/ + BOOST_PROTO_REPEAT_FROM_TO(1, BOOST_PP_INC(BOOST_PROTO_MAX_ARITY), M1) + #undef M1 + + template<typename Ret, typename Expr> + Expr const &ret(Expr const &expr) + { + return expr; + } + + template<typename Expr> + Expr const &const_parameters(Expr const &expr) + { + return expr; + } + + template<typename Expr> + Expr const &break_const(Expr const &expr) + { + return expr; + } + + template<typename Lambda> + proto::unexpr<Lambda> const + unlambda(Lambda const &lambda) + { + return proto::unexpr<Lambda>(lambda); + } + + template<typename Lambda> + typename proto::result_of::make_expr< + tag::protect + , lldomain + , Lambda const & + >::type const + protect(Lambda const &lambda) + { + return proto::make_expr<tag::protect, lldomain>(boost::ref(lambda)); + } + + template<typename T> + T const std_functor(T const &t) + { + return t; + } + + template<typename T> + struct ll_static_cast_fun + { + typedef T result_type; + + template<typename U> + T operator()(U &u) const + { + return static_cast<T>(u); + } + + template<typename U> + T operator()(U const &u) const + { + return static_cast<T>(u); + } + }; + + template<typename T, typename U> + typename proto::result_of::make_expr< + proto::tag::function + , lldomain + , ll_static_cast_fun<T> + , U const & + >::type + ll_static_cast(U const &u) + { + ll_static_cast_fun<T> fun; + return proto::make_expr<proto::tag::function, lldomain>(fun, boost::ref(u)); + } + + template<typename T> + struct ll_const_cast_fun + { + typedef T result_type; + + template<typename U> + T operator()(U &u) const + { + return const_cast<T>(u); + } + + template<typename U> + T operator()(U const &u) const + { + return const_cast<T>(u); + } + }; + + template<typename T, typename U> + typename proto::result_of::make_expr< + proto::tag::function + , lldomain + , ll_const_cast_fun<T> + , U const & + >::type + ll_const_cast(U const &u) + { + ll_const_cast_fun<T> fun; + return proto::make_expr<proto::tag::function, lldomain>(fun, boost::ref(u)); + } + + template<typename T> + struct ll_dynamic_cast_fun + { + typedef T result_type; + + template<typename U> + T operator()(U &u) const + { + return dynamic_cast<T>(u); + } + + template<typename U> + T operator()(U const &u) const + { + return dynamic_cast<T>(u); + } + }; + + template<typename T, typename U> + typename proto::result_of::make_expr< + proto::tag::function + , lldomain + , ll_dynamic_cast_fun<T> + , U const & + >::type + ll_dynamic_cast(U const &u) + { + ll_dynamic_cast_fun<T> fun; + return proto::make_expr<proto::tag::function, lldomain>(fun, boost::ref(u)); + } + + template<typename T> + struct ll_reinterpret_cast_fun + { + typedef T result_type; + + template<typename U> + T operator()(U &u) const + { + return reinterpret_cast<T>(u); + } + + template<typename U> + T operator()(U const &u) const + { + return reinterpret_cast<T>(u); + } + }; + + template<typename T, typename U> + typename proto::result_of::make_expr< + proto::tag::function + , lldomain + , ll_reinterpret_cast_fun<T> + , U const & + >::type + ll_reinterpret_cast(U const &u) + { + ll_reinterpret_cast_fun<T> fun; + return proto::make_expr<proto::tag::function, lldomain>(fun, boost::ref(u)); + } + + struct ll_sizeof_fun + { + typedef std::size_t result_type; + + template<typename U> + std::size_t operator()(U const &) const + { + return sizeof(U); + } + }; + + template<typename U> + typename proto::result_of::make_expr< + proto::tag::function + , lldomain + , ll_sizeof_fun + , U const & + >::type + ll_sizeof(U const &u) + { + ll_sizeof_fun fun; + return proto::make_expr<proto::tag::function, lldomain>(fun, boost::ref(u)); + } + + struct ll_typeid_fun + { + typedef std::type_info const &result_type; + + template<typename U> + std::type_info const &operator()(U const &) const + { + return typeid(U); + } + }; + + template<typename U> + typename proto::result_of::make_expr< + proto::tag::function + , lldomain + , ll_typeid_fun + , U const & + >::type + ll_typeid(U const &u) + { + ll_typeid_fun fun; + return proto::make_expr<proto::tag::function, lldomain>(fun, boost::ref(u)); + } + + template<typename T> + struct constructor + { + typedef T result_type; + + T operator()() const + { + return T(); + } + + #define M0(Z, N, DATA) \ + template<BOOST_PP_ENUM_PARAMS_Z(Z, N, typename A)> \ + T operator()(BOOST_PP_ENUM_BINARY_PARAMS_Z(Z, N, A, const &a)) const \ + { \ + return T(BOOST_PP_ENUM_PARAMS_Z(Z, N, a)); \ + } \ + /**/ + BOOST_PP_REPEAT_FROM_TO(1, BOOST_PROTO_MAX_ARITY, M0, ~) + #undef M0 + }; + + template<typename T> + struct new_ptr + { + typedef T *result_type; + + T *operator()() const + { + return new T(); + } + + #define M0(Z, N, DATA) \ + template<BOOST_PP_ENUM_PARAMS_Z(Z, N, typename A)> \ + T *operator()(BOOST_PP_ENUM_BINARY_PARAMS_Z(Z, N, A, const &a)) const \ + { \ + return new T(BOOST_PP_ENUM_PARAMS_Z(Z, N, a)); \ + } \ + /**/ + BOOST_PP_REPEAT_FROM_TO(1, BOOST_PROTO_MAX_ARITY, M0, ~) + #undef M0 + }; + + struct destructor + { + typedef void result_type; + + template<typename T> + void operator()(T const &t) const + { + t.~T(); + } + + template<typename T> + void operator()(T *const &t) const + { + (*t).~T(); + } + }; + + struct delete_ptr + { + typedef void result_type; + template<typename T> + void operator()(T *t) const + { + delete t; + } + }; + + template<typename T> + struct new_array + { + typedef T *result_type; + T *operator()(std::size_t n) const + { + return new T[n]; + } + }; + + struct delete_array + { + typedef void result_type; + template<typename T> + void operator()(T *t) const + { + delete[] t; + } + }; + + template<typename T> + struct type2type {}; + + struct try_catch_nil {}; + + template<typename Head, typename Tail> + struct try_catch_cons : Tail + { + typedef typename Head::proto_tag::exception_type exception_type; + + try_catch_cons(Head const &head, Tail const &tail) + : Tail(tail) + , head(head) + {} + + template<typename State, typename Data> + typename result_of<Tail const(State const &, Data &)>::type + operator()(State const &state, Data &data) const + { + return this->invoke(state, data, type2type<exception_type>()); + } + + private: + // catch(Exception const &) + template<typename State, typename Data, typename Exception> + typename result_of<Tail const(State const &, Data &)>::type + invoke(State const &state, Data &data, type2type<Exception>) const + { + typedef typename result_of<Tail const(State const &, Data &)>::type result_type; + try + { + return static_cast<result_type>(this->Tail::operator()(state, data)); + } + catch(Exception const &e) + { + return static_cast<result_type>(eval_lambda(this->head, e, data)); + } + } + + // catch(...) + template<typename State, typename Data> + typename result_of<Tail const(State const &, Data &)>::type + invoke(State const &state, Data &data, type2type<tag::catch_all_>) const + { + typedef typename result_of<Tail const(State const &, Data &)>::type result_type; + try + { + return static_cast<result_type>(this->Tail::operator()(state, data)); + } + catch(...) + { + return static_cast<result_type>(eval_lambda(this->head, tag::catch_all_(), data)); + } + } + + Head const &head; + }; + + template<typename Head> + struct try_catch_cons<Head, try_catch_nil> : proto::callable + { + try_catch_cons(Head const &head, try_catch_nil const &) + : head(head) + {} + + template<typename Sig> + struct result; + + template<typename This, typename State, typename Data> + struct result<This(State, Data)> + : result_of<Eval(Head const &, State, Data)> + {}; + + template<typename State, typename Data> + typename result_of<Eval(Head const &, State, Data)>::type + operator()(State const &state, Data &data) const + { + return eval_lambda(this->head, state, data); + } + + private: + Head const &head; + }; + + struct try_catch_fun : proto::callable + { + template<typename Sig> + struct result; + + template<typename This, typename Fun, typename State, typename Data> + struct result<This(Fun, State, Data)> + : result_of<Fun(State, Data)> + {}; + + template<typename Fun, typename State, typename Data> + typename result_of<Fun(State const &, Data &)>::type + operator()(Fun const &fun, State const &state, Data &data) const + { + return fun(state, data); + } + }; + + template<> + struct Cases::case_<tag::try_> + : proto::otherwise< + try_catch_fun( + proto::fold< + proto::_ + , try_catch_nil() + , try_catch_cons<proto::_, proto::_state>(proto::_, proto::_state) + > + , proto::_state + , proto::_data + ) + > + {}; + + template<typename E, typename Expr> + typename proto::result_of::make_expr<tag::catch_<E>, lldomain, Expr const &>::type const + catch_exception(Expr const &expr) + { + return proto::make_expr<tag::catch_<E>, lldomain>(boost::ref(expr)); + } + + template<typename E> + typename proto::result_of::make_expr<tag::catch_<E>, lldomain, noop_type const &>::type const + catch_exception() + { + return proto::make_expr<tag::catch_<E>, lldomain>(boost::ref(noop)); + } + + template<typename Expr> + typename proto::result_of::make_expr< + tag::catch_all_ + , lldomain + , Expr const & + >::type const + catch_all(Expr const &expr) + { + return proto::make_expr<tag::catch_all_, lldomain>(boost::ref(expr)); + } + + inline + proto::result_of::make_expr<tag::catch_all_, lldomain, noop_type const &>::type const + catch_all() + { + return proto::make_expr<tag::catch_all_, lldomain>(boost::ref(noop)); + } + + #define M1(N, typename_A, A_const_ref, A_const_ref_a, ref_a) \ + template<typename_A(N)> \ + typename proto::result_of::make_expr< \ + tag::try_ \ + , lldomain \ + , A_const_ref(N) \ + >::type const \ + try_catch(A_const_ref_a(N)) \ + { \ + return proto::make_expr<tag::try_, lldomain>(ref_a(N)); \ + } \ + /**/ + BOOST_PROTO_REPEAT_FROM_TO(2, BOOST_PP_INC(BOOST_PROTO_MAX_ARITY), M1) + #undef M1 + + template<typename Expr> + typename proto::result_of::make_expr< + proto::tag::function + , lldomain + , throw_fun + , Expr const & + >::type const + throw_exception(Expr const &expr) + { + throw_fun fun; + return proto::make_expr<proto::tag::function, lldomain>(fun, boost::ref(expr)); + } + + inline + proto::result_of::make_expr<proto::tag::function, lldomain, rethrow_fun>::type const + rethrow() + { + return proto::make_expr<proto::tag::function, lldomain>(rethrow_fun()); + } + + struct make_void_fun + { + typedef void result_type; + template<typename T> + void operator()(T const &) const + {} + }; + + template<typename Expr> + typename proto::result_of::make_expr< + proto::tag::function + , lldomain + , make_void_fun + , Expr const & + >::type const + make_void(Expr const &expr) + { + make_void_fun fun; + return proto::make_expr<proto::tag::function, lldomain>(fun, boost::ref(expr)); + } + + #define M1(N, typename_A, A_const_ref, A_const_ref_a, ref_a) \ + template<typename_A(N)> \ + typename proto::result_of::make_expr< \ + tag::switch_ \ + , lldomain \ + , A_const_ref(N) \ + >::type const \ + switch_statement(A_const_ref_a(N)) \ + { \ + return proto::make_expr<tag::switch_, lldomain>(ref_a(N)); \ + } \ + /**/ + BOOST_PROTO_REPEAT_FROM_TO(2, BOOST_PP_INC(BOOST_PROTO_MAX_ARITY), M1) + #undef M1 + + template<int I, typename Expr> + typename proto::result_of::make_expr<tag::case_<I>, lldomain, Expr const &>::type const + case_statement(Expr const &expr) + { + return proto::make_expr<tag::case_<I>, lldomain>(boost::ref(expr)); + } + + template<int I> + typename proto::result_of::make_expr<tag::case_<I>, lldomain, noop_type const &>::type const + case_statement() + { + return proto::make_expr<tag::case_<I>, lldomain>(boost::ref(noop)); + } + + template<typename Expr> + typename proto::result_of::make_expr<tag::default_, lldomain, Expr const &>::type const + default_statement(Expr const &expr) + { + return proto::make_expr<tag::default_, lldomain>(boost::ref(expr)); + } + + inline + proto::result_of::make_expr<tag::default_, lldomain, noop_type const &>::type const + default_statement() + { + return proto::make_expr<tag::default_, lldomain>(boost::ref(noop)); + } + + namespace ll + { + struct for_each + { + template<typename Sig> + struct result; + + template<typename This, typename Begin, typename End, typename Fun> + struct result<This(Begin, End, Fun)> + : remove_const<typename remove_reference<Fun>::type> + {}; + + template<typename InIter, typename Fun> + Fun operator()(InIter begin, InIter end, Fun fun) const + { + return std::for_each(begin, end, fun); + } + }; + } + + }} + + namespace boost + { + template<typename Expr> + struct result_of<lambda::llexpr<Expr>()> + : lambda::llexpr<Expr>::template result<lambda::llexpr<Expr>()> + {}; + + template<typename Expr> + struct result_of<lambda::llexpr<Expr> const()> + : lambda::llexpr<Expr>::template result<lambda::llexpr<Expr> const()> + {}; + } + + #ifdef _MSC_VER + # pragma warning(pop) + #endif + + #endif + +#else + + BOOST_PP_SEQ_FOR_EACH_PRODUCT( + M2, + BOOST_PP_REPEAT(BOOST_PP_ITERATION(), M1, ~) + ) + +#endif diff --git a/src/boost/libs/proto/example/lazy_vector.cpp b/src/boost/libs/proto/example/lazy_vector.cpp new file mode 100644 index 00000000..2fc7755c --- /dev/null +++ b/src/boost/libs/proto/example/lazy_vector.cpp @@ -0,0 +1,142 @@ +//[ LazyVector +/////////////////////////////////////////////////////////////////////////////// +// 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) +// +// This example constructs a mini-library for linear algebra, using +// expression templates to eliminate the need for temporaries when +// adding vectors of numbers. +// +// This example uses a domain with a grammar to prune the set +// of overloaded operators. Only those operators that produce +// valid lazy vector expressions are allowed. + +#include <vector> +#include <iostream> +#include <boost/mpl/int.hpp> +#include <boost/proto/core.hpp> +#include <boost/proto/context.hpp> +namespace mpl = boost::mpl; +namespace proto = boost::proto; +using proto::_; + +template<typename Expr> +struct lazy_vector_expr; + +// This grammar describes which lazy vector expressions +// are allowed; namely, vector terminals and addition +// and subtraction of lazy vector expressions. +struct LazyVectorGrammar + : proto::or_< + proto::terminal< std::vector<_> > + , proto::plus< LazyVectorGrammar, LazyVectorGrammar > + , proto::minus< LazyVectorGrammar, LazyVectorGrammar > + > +{}; + +// Tell proto that in the lazy_vector_domain, all +// expressions should be wrapped in laxy_vector_expr<> +// and must conform to the lazy vector grammar. +struct lazy_vector_domain + : proto::domain<proto::generator<lazy_vector_expr>, LazyVectorGrammar> +{}; + +// Here is an evaluation context that indexes into a lazy vector +// expression, and combines the result. +template<typename Size = std::size_t> +struct lazy_subscript_context +{ + lazy_subscript_context(Size subscript) + : subscript_(subscript) + {} + + // Use default_eval for all the operations ... + template<typename Expr, typename Tag = typename Expr::proto_tag> + struct eval + : proto::default_eval<Expr, lazy_subscript_context> + {}; + + // ... except for terminals, which we index with our subscript + template<typename Expr> + struct eval<Expr, proto::tag::terminal> + { + typedef typename proto::result_of::value<Expr>::type::value_type result_type; + + result_type operator ()( Expr const & expr, lazy_subscript_context & ctx ) const + { + return proto::value( expr )[ ctx.subscript_ ]; + } + }; + + Size subscript_; +}; + +// Here is the domain-specific expression wrapper, which overrides +// operator [] to evaluate the expression using the lazy_subscript_context. +template<typename Expr> +struct lazy_vector_expr + : proto::extends<Expr, lazy_vector_expr<Expr>, lazy_vector_domain> +{ + lazy_vector_expr( Expr const & expr = Expr() ) + : lazy_vector_expr::proto_extends( expr ) + {} + + // Use the lazy_subscript_context<> to implement subscripting + // of a lazy vector expression tree. + template< typename Size > + typename proto::result_of::eval< Expr, lazy_subscript_context<Size> >::type + operator []( Size subscript ) const + { + lazy_subscript_context<Size> ctx(subscript); + return proto::eval(*this, ctx); + } +}; + +// Here is our lazy_vector terminal, implemented in terms of lazy_vector_expr +template< typename T > +struct lazy_vector + : lazy_vector_expr< typename proto::terminal< std::vector<T> >::type > +{ + typedef typename proto::terminal< std::vector<T> >::type expr_type; + + lazy_vector( std::size_t size = 0, T const & value = T() ) + : lazy_vector_expr<expr_type>( expr_type::make( std::vector<T>( size, value ) ) ) + {} + + // Here we define a += operator for lazy vector terminals that + // takes a lazy vector expression and indexes it. expr[i] here + // uses lazy_subscript_context<> under the covers. + template< typename Expr > + lazy_vector &operator += (Expr const & expr) + { + std::size_t size = proto::value(*this).size(); + for(std::size_t i = 0; i < size; ++i) + { + proto::value(*this)[i] += expr[i]; + } + return *this; + } +}; + +int main() +{ + // lazy_vectors with 4 elements each. + lazy_vector< double > v1( 4, 1.0 ), v2( 4, 2.0 ), v3( 4, 3.0 ); + + // Add two vectors lazily and get the 2nd element. + double d1 = ( v2 + v3 )[ 2 ]; // Look ma, no temporaries! + std::cout << d1 << std::endl; + + // Subtract two vectors and add the result to a third vector. + v1 += v2 - v3; // Still no temporaries! + std::cout << '{' << v1[0] << ',' << v1[1] + << ',' << v1[2] << ',' << v1[3] << '}' << std::endl; + + // This expression is disallowed because it does not conform + // to the LazyVectorGrammar + //(v2 + v3) += v1; + + return 0; +} +//] diff --git a/src/boost/libs/proto/example/map_assign.cpp b/src/boost/libs/proto/example/map_assign.cpp new file mode 100644 index 00000000..93911059 --- /dev/null +++ b/src/boost/libs/proto/example/map_assign.cpp @@ -0,0 +1,136 @@ +//[ MapAssign +// 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) +// +// This is a port of map_list_of() from the Boost.Assign library. +// It has the advantage of being more efficient at runtime by not +// building any temporary container that requires dynamic allocation. + +#include <map> +#include <string> +#include <iostream> +#include <boost/proto/core.hpp> +#include <boost/proto/transform.hpp> +#include <boost/type_traits/add_reference.hpp> +namespace proto = boost::proto; +using proto::_; + +struct map_list_of_tag +{}; + +// A simple callable function object that inserts a +// (key,value) pair into a map. +struct insert + : proto::callable +{ + template<typename Sig> + struct result; + + template<typename This, typename Map, typename Key, typename Value> + struct result<This(Map, Key, Value)> + : boost::add_reference<Map> + {}; + + template<typename Map, typename Key, typename Value> + Map &operator()(Map &map, Key const &key, Value const &value) const + { + map.insert(typename Map::value_type(key, value)); + return map; + } +}; + +// Work-arounds for Microsoft Visual C++ 7.1 +#if BOOST_WORKAROUND(BOOST_MSVC, == 1310) +#define MapListOf(x) proto::call<MapListOf(x)> +#define _value(x) call<proto::_value(x)> +#endif + +// The grammar for valid map-list expressions, and a +// transform that populates the map. +struct MapListOf + : proto::or_< + proto::when< + // map_list_of(a,b) + proto::function< + proto::terminal<map_list_of_tag> + , proto::terminal<_> + , proto::terminal<_> + > + , insert( + proto::_data + , proto::_value(proto::_child1) + , proto::_value(proto::_child2) + ) + > + , proto::when< + // map_list_of(a,b)(c,d)... + proto::function< + MapListOf + , proto::terminal<_> + , proto::terminal<_> + > + , insert( + MapListOf(proto::_child0) + , proto::_value(proto::_child1) + , proto::_value(proto::_child2) + ) + > + > +{}; + +#if BOOST_WORKAROUND(BOOST_MSVC, == 1310) +#undef MapListOf +#undef _value +#endif + +template<typename Expr> +struct map_list_of_expr; + +struct map_list_of_dom + : proto::domain<proto::pod_generator<map_list_of_expr>, MapListOf> +{}; + +// An expression wrapper that provides a conversion to a +// map that uses the MapListOf +template<typename Expr> +struct map_list_of_expr +{ + BOOST_PROTO_BASIC_EXTENDS(Expr, map_list_of_expr, map_list_of_dom) + BOOST_PROTO_EXTENDS_FUNCTION() + + template<typename Key, typename Value, typename Cmp, typename Al> + operator std::map<Key, Value, Cmp, Al> () const + { + BOOST_MPL_ASSERT((proto::matches<Expr, MapListOf>)); + std::map<Key, Value, Cmp, Al> map; + return MapListOf()(*this, 0, map); + } +}; + +map_list_of_expr<proto::terminal<map_list_of_tag>::type> const map_list_of = {{{}}}; + +int main() +{ + // Initialize a map: + std::map<std::string, int> op = + map_list_of + ("<", 1) + ("<=",2) + (">", 3) + (">=",4) + ("=", 5) + ("<>",6) + ; + + std::cout << "\"<\" --> " << op["<"] << std::endl; + std::cout << "\"<=\" --> " << op["<="] << std::endl; + std::cout << "\">\" --> " << op[">"] << std::endl; + std::cout << "\">=\" --> " << op[">="] << std::endl; + std::cout << "\"=\" --> " << op["="] << std::endl; + std::cout << "\"<>\" --> " << op["<>"] << std::endl; + + return 0; +} +//] + diff --git a/src/boost/libs/proto/example/mini_lambda.cpp b/src/boost/libs/proto/example/mini_lambda.cpp new file mode 100644 index 00000000..0f3d52c6 --- /dev/null +++ b/src/boost/libs/proto/example/mini_lambda.cpp @@ -0,0 +1,263 @@ +//[ Lambda +/////////////////////////////////////////////////////////////////////////////// +// 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) +// +// This example builds a simple but functional lambda library using Proto. + +#include <iostream> +#include <algorithm> +#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/ostream.hpp> +#include <boost/typeof/std/iostream.hpp> +#include <boost/proto/core.hpp> +#include <boost/proto/context.hpp> +#include <boost/proto/transform.hpp> +namespace mpl = boost::mpl; +namespace proto = boost::proto; +namespace fusion = boost::fusion; +using proto::_; + +// 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; +}; + +// The lambda grammar, with the transforms for calculating the max arity +struct lambda_arity + : proto::or_< + proto::when< + proto::terminal< placeholder<_> > + , mpl::next<placeholder_arity<proto::_value> >() + > + , proto::when< proto::terminal<_> + , mpl::int_<0>() + > + , proto::when< + proto::nary_expr<_, proto::vararg<_> > + , proto::fold<_, mpl::int_<0>(), mpl::max<lambda_arity, proto::_state>()> + > + > +{}; + +// 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() + + // Calculate the arity of this lambda expression + static int const arity = boost::result_of<lambda_arity(T)>::type::value; + + template<typename Sig> + struct result; + + // Define nested result<> specializations to calculate the return + // type of this lambda expression. But be careful not to evaluate + // the return type of the nullary function unless we have a nullary + // lambda! + template<typename This> + struct result<This()> + : mpl::eval_if_c< + 0 == arity + , proto::result_of::eval<T const, lambda_context<fusion::tuple<> > > + , mpl::identity<void> + > + {}; + + template<typename This, typename A0> + struct result<This(A0)> + : proto::result_of::eval<T const, lambda_context<fusion::tuple<A0> > > + {}; + + template<typename This, typename A0, typename A1> + struct result<This(A0, A1)> + : proto::result_of::eval<T const, lambda_context<fusion::tuple<A0, A1> > > + {}; + + // Define our operator () that evaluates the lambda expression. + typename result<lambda()>::type + operator ()() const + { + fusion::tuple<> args; + lambda_context<fusion::tuple<> > ctx(args); + return proto::eval(*this, ctx); + } + + template<typename A0> + typename result<lambda(A0 const &)>::type + operator ()(A0 const &a0) const + { + fusion::tuple<A0 const &> args(a0); + lambda_context<fusion::tuple<A0 const &> > ctx(args); + return proto::eval(*this, ctx); + } + + template<typename A0, typename A1> + typename result<lambda(A0 const &, A1 const &)>::type + operator ()(A0 const &a0, A1 const &a1) const + { + fusion::tuple<A0 const &, A1 const &> args(a0, a1); + lambda_context<fusion::tuple<A0 const &, A1 const &> > ctx(args); + return proto::eval(*this, ctx); + } +}; + +// Define some lambda placeholders +lambda<proto::terminal<placeholder<mpl::int_<0> > >::type> const _1 = {{}}; +lambda<proto::terminal<placeholder<mpl::int_<1> > >::type> const _2 = {{}}; + +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; +} + +template<typename T> +struct construct_helper +{ + typedef T result_type; // for TR1 result_of + + T operator()() const + { return T(); } + + // Generate BOOST_PROTO_MAX_ARITY overloads of the + // following function call operator. +#define BOOST_PROTO_LOCAL_MACRO(N, typename_A, A_const_ref, A_const_ref_a, a)\ + template<typename_A(N)> \ + T operator()(A_const_ref_a(N)) const \ + { return T(a(N)); } +#define BOOST_PROTO_LOCAL_a BOOST_PROTO_a +#include BOOST_PROTO_LOCAL_ITERATE() +}; + +// Generate BOOST_PROTO_MAX_ARITY-1 overloads of the +// following construct() function template. +#define M0(N, typename_A, A_const_ref, A_const_ref_a, ref_a) \ +template<typename T, typename_A(N)> \ +typename proto::result_of::make_expr< \ + proto::tag::function \ + , lambda_domain \ + , construct_helper<T> \ + , A_const_ref(N) \ +>::type const \ +construct(A_const_ref_a(N)) \ +{ \ + return proto::make_expr< \ + proto::tag::function \ + , lambda_domain \ + >( \ + construct_helper<T>() \ + , ref_a(N) \ + ); \ +} +BOOST_PROTO_REPEAT_FROM_TO(1, BOOST_PROTO_MAX_ARITY, M0) +#undef M0 + +struct S +{ + S() {} + S(int i, char c) + { + std::cout << "S(" << i << "," << c << ")\n"; + } +}; + +int main() +{ + // Create some lambda objects and immediately + // invoke them by applying their operator(): + int i = ( (_1 + 2) / 4 )(42); + std::cout << i << std::endl; // prints 11 + + int j = ( (-(_1 + 2)) / 4 )(42); + std::cout << j << std::endl; // prints -11 + + double d = ( (4 - _2) * 3 )(42, 3.14); + std::cout << d << std::endl; // prints 2.58 + + // check non-const ref terminals + (std::cout << _1 << " -- " << _2 << '\n')(42, "Life, the Universe and Everything!"); + // prints "42 -- Life, the Universe and Everything!" + + // "Nullary" lambdas work too + int k = (val(1) + val(2))(); + std::cout << k << std::endl; // prints 3 + + // check array indexing for kicks + int integers[5] = {0}; + (var(integers)[2] = 2)(); + (var(integers)[_1] = _1)(3); + std::cout << integers[2] << std::endl; // prints 2 + std::cout << integers[3] << std::endl; // prints 3 + + // Now use a lambda with an STL algorithm! + int rgi[4] = {1,2,3,4}; + char rgc[4] = {'a','b','c','d'}; + S rgs[4]; + + std::transform(rgi, rgi+4, rgc, rgs, construct<S>(_1, _2)); + return 0; +} +//] diff --git a/src/boost/libs/proto/example/mixed.cpp b/src/boost/libs/proto/example/mixed.cpp new file mode 100644 index 00000000..d48e21dc --- /dev/null +++ b/src/boost/libs/proto/example/mixed.cpp @@ -0,0 +1,375 @@ +//[ Mixed +/////////////////////////////////////////////////////////////////////////////// +// 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) +// +// This is an example of using BOOST_PROTO_DEFINE_OPERATORS to Protofy +// expressions using std::vector<> and std::list, non-proto types. It is a port +// of the Mixed example from PETE. +// (http://www.codesourcery.com/pooma/download.html). + +#include <list> +#include <cmath> +#include <vector> +#include <complex> +#include <iostream> +#include <stdexcept> +#include <boost/proto/core.hpp> +#include <boost/proto/debug.hpp> +#include <boost/proto/context.hpp> +#include <boost/proto/transform.hpp> +#include <boost/utility/enable_if.hpp> +#include <boost/typeof/std/list.hpp> +#include <boost/typeof/std/vector.hpp> +#include <boost/typeof/std/complex.hpp> +#include <boost/type_traits/remove_reference.hpp> +namespace proto = boost::proto; +namespace mpl = boost::mpl; +using proto::_; + +template<typename Expr> +struct MixedExpr; + +template<typename Iter> +struct iterator_wrapper +{ + typedef Iter iterator; + + explicit iterator_wrapper(Iter iter) + : it(iter) + {} + + mutable Iter it; +}; + +struct begin : proto::callable +{ + template<class Sig> + struct result; + + template<class This, class Cont> + struct result<This(Cont)> + : proto::result_of::as_expr< + iterator_wrapper<typename boost::remove_reference<Cont>::type::const_iterator> + > + {}; + + template<typename Cont> + typename result<begin(Cont const &)>::type + operator ()(Cont const &cont) const + { + iterator_wrapper<typename Cont::const_iterator> it(cont.begin()); + return proto::as_expr(it); + } +}; + +// Here is a grammar that replaces vector and list terminals with their +// begin iterators +struct Begin + : proto::or_< + proto::when< proto::terminal< std::vector<_, _> >, begin(proto::_value) > + , proto::when< proto::terminal< std::list<_, _> >, begin(proto::_value) > + , proto::when< proto::terminal<_> > + , proto::when< proto::nary_expr<_, proto::vararg<Begin> > > + > +{}; + +// Here is an evaluation context that dereferences iterator +// terminals. +struct DereferenceCtx +{ + // Unless this is an iterator terminal, use the + // default evaluation context + template<typename Expr, typename EnableIf = void> + struct eval + : proto::default_eval<Expr, DereferenceCtx const> + {}; + + // Dereference iterator terminals. + template<typename Expr> + struct eval< + Expr + , typename boost::enable_if< + proto::matches<Expr, proto::terminal<iterator_wrapper<_> > > + >::type + > + { + typedef typename proto::result_of::value<Expr>::type IteratorWrapper; + typedef typename IteratorWrapper::iterator iterator; + typedef typename std::iterator_traits<iterator>::reference result_type; + + result_type operator ()(Expr &expr, DereferenceCtx const &) const + { + return *proto::value(expr).it; + } + }; +}; + +// Here is an evaluation context that increments iterator +// terminals. +struct IncrementCtx +{ + // Unless this is an iterator terminal, use the + // default evaluation context + template<typename Expr, typename EnableIf = void> + struct eval + : proto::null_eval<Expr, IncrementCtx const> + {}; + + // advance iterator terminals. + template<typename Expr> + struct eval< + Expr + , typename boost::enable_if< + proto::matches<Expr, proto::terminal<iterator_wrapper<_> > > + >::type + > + { + typedef void result_type; + + result_type operator ()(Expr &expr, IncrementCtx const &) const + { + ++proto::value(expr).it; + } + }; +}; + +// A grammar which matches all the assignment operators, +// so we can easily disable them. +struct AssignOps + : proto::switch_<struct AssignOpsCases> +{}; + +// Here are the cases used by the switch_ above. +struct AssignOpsCases +{ + template<typename Tag, int D = 0> struct case_ : proto::not_<_> {}; + + template<int D> struct case_< proto::tag::plus_assign, D > : _ {}; + template<int D> struct case_< proto::tag::minus_assign, D > : _ {}; + template<int D> struct case_< proto::tag::multiplies_assign, D > : _ {}; + template<int D> struct case_< proto::tag::divides_assign, D > : _ {}; + template<int D> struct case_< proto::tag::modulus_assign, D > : _ {}; + template<int D> struct case_< proto::tag::shift_left_assign, D > : _ {}; + template<int D> struct case_< proto::tag::shift_right_assign, D > : _ {}; + template<int D> struct case_< proto::tag::bitwise_and_assign, D > : _ {}; + template<int D> struct case_< proto::tag::bitwise_or_assign, D > : _ {}; + template<int D> struct case_< proto::tag::bitwise_xor_assign, D > : _ {}; +}; + +// An expression conforms to the MixedGrammar if it is a terminal or some +// op that is not an assignment op. (Assignment will be handled specially.) +struct MixedGrammar + : proto::or_< + proto::terminal<_> + , proto::and_< + proto::nary_expr<_, proto::vararg<MixedGrammar> > + , proto::not_<AssignOps> + > + > +{}; + +// Expressions in the MixedDomain will be wrapped in MixedExpr<> +// and must conform to the MixedGrammar +struct MixedDomain + : proto::domain<proto::generator<MixedExpr>, MixedGrammar> +{}; + +// Here is MixedExpr, a wrapper for expression types in the MixedDomain. +template<typename Expr> +struct MixedExpr + : proto::extends<Expr, MixedExpr<Expr>, MixedDomain> +{ + explicit MixedExpr(Expr const &expr) + : MixedExpr::proto_extends(expr) + {} +private: + // hide this: + using proto::extends<Expr, MixedExpr<Expr>, MixedDomain>::operator []; +}; + +// Define a trait type for detecting vector and list terminals, to +// be used by the BOOST_PROTO_DEFINE_OPERATORS macro below. +template<typename T> +struct IsMixed + : mpl::false_ +{}; + +template<typename T, typename A> +struct IsMixed<std::list<T, A> > + : mpl::true_ +{}; + +template<typename T, typename A> +struct IsMixed<std::vector<T, A> > + : mpl::true_ +{}; + +namespace MixedOps +{ + // This defines all the overloads to make expressions involving + // std::vector to build expression templates. + BOOST_PROTO_DEFINE_OPERATORS(IsMixed, MixedDomain) + + struct assign_op + { + template<typename T, typename U> + void operator ()(T &t, U const &u) const + { + t = u; + } + }; + + struct plus_assign_op + { + template<typename T, typename U> + void operator ()(T &t, U const &u) const + { + t += u; + } + }; + + struct minus_assign_op + { + template<typename T, typename U> + void operator ()(T &t, U const &u) const + { + t -= u; + } + }; + + struct sin_ + { + template<typename Sig> + struct result; + + template<typename This, typename Arg> + struct result<This(Arg)> + : boost::remove_const<typename boost::remove_reference<Arg>::type> + {}; + + template<typename Arg> + Arg operator ()(Arg const &a) const + { + return std::sin(a); + } + }; + + template<typename A> + typename proto::result_of::make_expr< + proto::tag::function + , MixedDomain + , sin_ const + , A const & + >::type sin(A const &a) + { + return proto::make_expr<proto::tag::function, MixedDomain>(sin_(), boost::ref(a)); + } + + template<typename FwdIter, typename Expr, typename Op> + void evaluate(FwdIter begin, FwdIter end, Expr const &expr, Op op) + { + IncrementCtx const inc = {}; + DereferenceCtx const deref = {}; + typename boost::result_of<Begin(Expr const &)>::type expr2 = Begin()(expr); + for(; begin != end; ++begin) + { + op(*begin, proto::eval(expr2, deref)); + proto::eval(expr2, inc); + } + } + + // Add-assign to a vector from some expression. + template<typename T, typename A, typename Expr> + std::vector<T, A> &assign(std::vector<T, A> &arr, Expr const &expr) + { + evaluate(arr.begin(), arr.end(), proto::as_expr<MixedDomain>(expr), assign_op()); + return arr; + } + + // Add-assign to a list from some expression. + template<typename T, typename A, typename Expr> + std::list<T, A> &assign(std::list<T, A> &arr, Expr const &expr) + { + evaluate(arr.begin(), arr.end(), proto::as_expr<MixedDomain>(expr), assign_op()); + return arr; + } + + // Add-assign to a vector from some expression. + template<typename T, typename A, typename Expr> + std::vector<T, A> &operator +=(std::vector<T, A> &arr, Expr const &expr) + { + evaluate(arr.begin(), arr.end(), proto::as_expr<MixedDomain>(expr), plus_assign_op()); + return arr; + } + + // Add-assign to a list from some expression. + template<typename T, typename A, typename Expr> + std::list<T, A> &operator +=(std::list<T, A> &arr, Expr const &expr) + { + evaluate(arr.begin(), arr.end(), proto::as_expr<MixedDomain>(expr), plus_assign_op()); + return arr; + } + + // Minus-assign to a vector from some expression. + template<typename T, typename A, typename Expr> + std::vector<T, A> &operator -=(std::vector<T, A> &arr, Expr const &expr) + { + evaluate(arr.begin(), arr.end(), proto::as_expr<MixedDomain>(expr), minus_assign_op()); + return arr; + } + + // Minus-assign to a list from some expression. + template<typename T, typename A, typename Expr> + std::list<T, A> &operator -=(std::list<T, A> &arr, Expr const &expr) + { + evaluate(arr.begin(), arr.end(), proto::as_expr<MixedDomain>(expr), minus_assign_op()); + return arr; + } +} + +int main() +{ + using namespace MixedOps; + + int n = 10; + std::vector<int> a,b,c,d; + std::list<double> e; + std::list<std::complex<double> > f; + + int i; + for(i = 0;i < n; ++i) + { + a.push_back(i); + b.push_back(2*i); + c.push_back(3*i); + d.push_back(i); + e.push_back(0.0); + f.push_back(std::complex<double>(1.0, 1.0)); + } + + MixedOps::assign(b, 2); + MixedOps::assign(d, a + b * c); + a += if_else(d < 30, b, c); + + MixedOps::assign(e, c); + e += e - 4 / (c + 1); + + f -= sin(0.1 * e * std::complex<double>(0.2, 1.2)); + + std::list<double>::const_iterator ei = e.begin(); + std::list<std::complex<double> >::const_iterator fi = f.begin(); + for (i = 0; i < n; ++i) + { + std::cout + << "a(" << i << ") = " << a[i] + << " b(" << i << ") = " << b[i] + << " c(" << i << ") = " << c[i] + << " d(" << i << ") = " << d[i] + << " e(" << i << ") = " << *ei++ + << " f(" << i << ") = " << *fi++ + << std::endl; + } +} +//] diff --git a/src/boost/libs/proto/example/rgb.cpp b/src/boost/libs/proto/example/rgb.cpp new file mode 100644 index 00000000..51b0f459 --- /dev/null +++ b/src/boost/libs/proto/example/rgb.cpp @@ -0,0 +1,102 @@ +//[ RGB +/////////////////////////////////////////////////////////////////////////////// +// 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) +// +// This is a simple example of doing arbitrary type manipulations with proto +// transforms. It takes some expression involving primary colors and combines +// the colors according to arbitrary rules. It is a port of the RGB example +// from PETE (http://www.codesourcery.com/pooma/download.html). + +#include <iostream> +#include <boost/proto/core.hpp> +#include <boost/proto/transform.hpp> +namespace proto = boost::proto; + +struct RedTag +{ + friend std::ostream &operator <<(std::ostream &sout, RedTag) + { + return sout << "This expression is red."; + } +}; + +struct BlueTag +{ + friend std::ostream &operator <<(std::ostream &sout, BlueTag) + { + return sout << "This expression is blue."; + } +}; + +struct GreenTag +{ + friend std::ostream &operator <<(std::ostream &sout, GreenTag) + { + return sout << "This expression is green."; + } +}; + +typedef proto::terminal<RedTag>::type RedT; +typedef proto::terminal<BlueTag>::type BlueT; +typedef proto::terminal<GreenTag>::type GreenT; + +struct Red; +struct Blue; +struct Green; + +/////////////////////////////////////////////////////////////////////////////// +// A transform that produces new colors according to some arbitrary rules: +// red & green give blue, red & blue give green, blue and green give red. +struct Red + : proto::or_< + proto::plus<Green, Blue> + , proto::plus<Blue, Green> + , proto::plus<Red, Red> + , proto::terminal<RedTag> + > +{}; + +struct Green + : proto::or_< + proto::plus<Red, Blue> + , proto::plus<Blue, Red> + , proto::plus<Green, Green> + , proto::terminal<GreenTag> + > +{}; + +struct Blue + : proto::or_< + proto::plus<Red, Green> + , proto::plus<Green, Red> + , proto::plus<Blue, Blue> + , proto::terminal<BlueTag> + > +{}; + +struct RGB + : proto::or_< + proto::when< Red, RedTag() > + , proto::when< Blue, BlueTag() > + , proto::when< Green, GreenTag() > + > +{}; + +template<typename Expr> +void printColor(Expr const & expr) +{ + int i = 0; // dummy state and data parameter, not used + std::cout << RGB()(expr, i, i) << std::endl; +} + +int main() +{ + printColor(RedT() + GreenT()); + printColor(RedT() + GreenT() + BlueT()); + printColor(RedT() + (GreenT() + BlueT())); + + return 0; +} +//] diff --git a/src/boost/libs/proto/example/tarray.cpp b/src/boost/libs/proto/example/tarray.cpp new file mode 100644 index 00000000..338f69b1 --- /dev/null +++ b/src/boost/libs/proto/example/tarray.cpp @@ -0,0 +1,222 @@ +//[ TArray +/////////////////////////////////////////////////////////////////////////////// +// 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) +// +// This example constructs a mini-library for linear algebra, using +// expression templates to eliminate the need for temporaries when +// adding arrays of numbers. It duplicates the TArray example from +// PETE (http://www.codesourcery.com/pooma/download.html) + +#include <iostream> +#include <boost/mpl/int.hpp> +#include <boost/proto/core.hpp> +#include <boost/proto/context.hpp> +namespace mpl = boost::mpl; +namespace proto = boost::proto; +using proto::_; + +// This grammar describes which TArray expressions +// are allowed; namely, int and array terminals +// plus, minus, multiplies and divides of TArray expressions. +struct TArrayGrammar + : proto::or_< + proto::terminal< int > + , proto::terminal< int[3] > + , proto::plus< TArrayGrammar, TArrayGrammar > + , proto::minus< TArrayGrammar, TArrayGrammar > + , proto::multiplies< TArrayGrammar, TArrayGrammar > + , proto::divides< TArrayGrammar, TArrayGrammar > + > +{}; + +template<typename Expr> +struct TArrayExpr; + +// Tell proto that in the TArrayDomain, all +// expressions should be wrapped in TArrayExpr<> and +// must conform to the TArrayGrammar +struct TArrayDomain + : proto::domain<proto::generator<TArrayExpr>, TArrayGrammar> +{}; + +// Here is an evaluation context that indexes into a TArray +// expression, and combines the result. +struct TArraySubscriptCtx + : proto::callable_context< TArraySubscriptCtx const > +{ + typedef int result_type; + + TArraySubscriptCtx(std::ptrdiff_t i) + : i_(i) + {} + + // Index array terminals with our subscript. Everything + // else will be handled by the default evaluation context. + int operator ()(proto::tag::terminal, int const (&data)[3]) const + { + return data[this->i_]; + } + + std::ptrdiff_t i_; +}; + +// Here is an evaluation context that prints a TArray expression. +struct TArrayPrintCtx + : proto::callable_context< TArrayPrintCtx const > +{ + typedef std::ostream &result_type; + + TArrayPrintCtx() {} + + std::ostream &operator ()(proto::tag::terminal, int i) const + { + return std::cout << i; + } + + std::ostream &operator ()(proto::tag::terminal, int const (&arr)[3]) const + { + return std::cout << '{' << arr[0] << ", " << arr[1] << ", " << arr[2] << '}'; + } + + template<typename L, typename R> + std::ostream &operator ()(proto::tag::plus, L const &l, R const &r) const + { + return std::cout << '(' << l << " + " << r << ')'; + } + + template<typename L, typename R> + std::ostream &operator ()(proto::tag::minus, L const &l, R const &r) const + { + return std::cout << '(' << l << " - " << r << ')'; + } + + template<typename L, typename R> + std::ostream &operator ()(proto::tag::multiplies, L const &l, R const &r) const + { + return std::cout << l << " * " << r; + } + + template<typename L, typename R> + std::ostream &operator ()(proto::tag::divides, L const &l, R const &r) const + { + return std::cout << l << " / " << r; + } +}; + +// Here is the domain-specific expression wrapper, which overrides +// operator [] to evaluate the expression using the TArraySubscriptCtx. +template<typename Expr> +struct TArrayExpr + : proto::extends<Expr, TArrayExpr<Expr>, TArrayDomain> +{ + typedef proto::extends<Expr, TArrayExpr<Expr>, TArrayDomain> base_type; + + TArrayExpr( Expr const & expr = Expr() ) + : base_type( expr ) + {} + + // Use the TArraySubscriptCtx to implement subscripting + // of a TArray expression tree. + int operator []( std::ptrdiff_t i ) const + { + TArraySubscriptCtx const ctx(i); + return proto::eval(*this, ctx); + } + + // Use the TArrayPrintCtx to display a TArray expression tree. + friend std::ostream &operator <<(std::ostream &sout, TArrayExpr<Expr> const &expr) + { + TArrayPrintCtx const ctx; + return proto::eval(expr, ctx); + } +}; + +// Here is our TArray terminal, implemented in terms of TArrayExpr +// It is basically just an array of 3 integers. +struct TArray + : TArrayExpr< proto::terminal< int[3] >::type > +{ + explicit TArray( int i = 0, int j = 0, int k = 0 ) + { + (*this)[0] = i; + (*this)[1] = j; + (*this)[2] = k; + } + + // Here we override operator [] to give read/write access to + // the elements of the array. (We could use the TArrayExpr + // operator [] if we made the subscript context smarter about + // returning non-const reference when appropriate.) + int &operator [](std::ptrdiff_t i) + { + return proto::value(*this)[i]; + } + + int const &operator [](std::ptrdiff_t i) const + { + return proto::value(*this)[i]; + } + + // Here we define a operator = for TArray terminals that + // takes a TArray expression. + template< typename Expr > + TArray &operator =(Expr const & expr) + { + // proto::as_expr<TArrayDomain>(expr) is the same as + // expr unless expr is an integer, in which case it + // is made into a TArrayExpr terminal first. + return this->assign(proto::as_expr<TArrayDomain>(expr)); + } + + template< typename Expr > + TArray &printAssign(Expr const & expr) + { + *this = expr; + std::cout << *this << " = " << expr << std::endl; + return *this; + } + +private: + template< typename Expr > + TArray &assign(Expr const & expr) + { + // expr[i] here uses TArraySubscriptCtx under the covers. + (*this)[0] = expr[0]; + (*this)[1] = expr[1]; + (*this)[2] = expr[2]; + return *this; + } +}; + +int main() +{ + TArray a(3,1,2); + + TArray b; + + std::cout << a << std::endl; + std::cout << b << std::endl; + + b[0] = 7; b[1] = 33; b[2] = -99; + + TArray c(a); + + std::cout << c << std::endl; + + a = 0; + + std::cout << a << std::endl; + std::cout << b << std::endl; + std::cout << c << std::endl; + + a = b + c; + + std::cout << a << std::endl; + + a.printAssign(b+c*(b + 3*c)); + + return 0; +} +//] diff --git a/src/boost/libs/proto/example/vec3.cpp b/src/boost/libs/proto/example/vec3.cpp new file mode 100644 index 00000000..2da94872 --- /dev/null +++ b/src/boost/libs/proto/example/vec3.cpp @@ -0,0 +1,184 @@ +//[ Vec3 +/////////////////////////////////////////////////////////////////////////////// +// 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) +// +// This is a simple example using proto::extends to extend a terminal type with +// additional behaviors, and using custom contexts and proto::eval for +// evaluating expressions. It is a port of the Vec3 example +// from PETE (http://www.codesourcery.com/pooma/download.html). + +#include <iostream> +#include <functional> +#include <boost/assert.hpp> +#include <boost/mpl/int.hpp> +#include <boost/proto/core.hpp> +#include <boost/proto/context.hpp> +#include <boost/proto/proto_typeof.hpp> +#include <boost/proto/transform.hpp> +namespace mpl = boost::mpl; +namespace proto = boost::proto; +using proto::_; + +// Here is an evaluation context that indexes into a Vec3 +// expression, and combines the result. +struct Vec3SubscriptCtx + : proto::callable_context< Vec3SubscriptCtx const > +{ + typedef int result_type; + + Vec3SubscriptCtx(int i) + : i_(i) + {} + + // Index array terminals with our subscript. Everything + // else will be handled by the default evaluation context. + int operator ()(proto::tag::terminal, int const (&arr)[3]) const + { + return arr[this->i_]; + } + + int i_; +}; + +// Here is an evaluation context that counts the number +// of Vec3 terminals in an expression. +struct CountLeavesCtx + : proto::callable_context< CountLeavesCtx, proto::null_context > +{ + CountLeavesCtx() + : count(0) + {} + + typedef void result_type; + + void operator ()(proto::tag::terminal, int const(&)[3]) + { + ++this->count; + } + + int count; +}; + +struct iplus : std::plus<int>, proto::callable {}; + +// Here is a transform that does the same thing as the above context. +// It demonstrates the use of the std::plus<> function object +// with the fold transform. With minor modifications, this +// transform could be used to calculate the leaf count at compile +// time, rather than at runtime. +struct CountLeaves + : proto::or_< + // match a Vec3 terminal, return 1 + proto::when<proto::terminal<int[3]>, mpl::int_<1>() > + // match a terminal, return int() (which is 0) + , proto::when<proto::terminal<_>, int() > + // fold everything else, using std::plus<> to add + // the leaf count of each child to the accumulated state. + , proto::otherwise< proto::fold<_, int(), iplus(CountLeaves, proto::_state) > > + > +{}; + +// Here is the Vec3 struct, which is a vector of 3 integers. +struct Vec3 + : proto::extends<proto::terminal<int[3]>::type, Vec3> +{ + explicit Vec3(int i=0, int j=0, int k=0) + { + (*this)[0] = i; + (*this)[1] = j; + (*this)[2] = k; + } + + int &operator [](int i) + { + return proto::value(*this)[i]; + } + + int const &operator [](int i) const + { + return proto::value(*this)[i]; + } + + // Here we define a operator = for Vec3 terminals that + // takes a Vec3 expression. + template< typename Expr > + Vec3 &operator =(Expr const & expr) + { + typedef Vec3SubscriptCtx const CVec3SubscriptCtx; + (*this)[0] = proto::eval(proto::as_expr(expr), CVec3SubscriptCtx(0)); + (*this)[1] = proto::eval(proto::as_expr(expr), CVec3SubscriptCtx(1)); + (*this)[2] = proto::eval(proto::as_expr(expr), CVec3SubscriptCtx(2)); + return *this; + } + + // This copy-assign is needed because a template is never + // considered for copy assignment. + Vec3 &operator=(Vec3 const &that) + { + (*this)[0] = that[0]; + (*this)[1] = that[1]; + (*this)[2] = that[2]; + return *this; + } + + void print() const + { + std::cout << '{' << (*this)[0] + << ", " << (*this)[1] + << ", " << (*this)[2] + << '}' << std::endl; + } +}; + +// The count_leaves() function uses the CountLeaves transform and +// to count the number of leaves in an expression. +template<typename Expr> +int count_leaves(Expr const &expr) +{ + // Count the number of Vec3 terminals using the + // CountLeavesCtx evaluation context. + CountLeavesCtx ctx; + proto::eval(expr, ctx); + + // This is another way to count the leaves using a transform. + int i = 0; + BOOST_ASSERT( CountLeaves()(expr, i, i) == ctx.count ); + + return ctx.count; +} + +int main() +{ + Vec3 a, b, c; + + c = 4; + + b[0] = -1; + b[1] = -2; + b[2] = -3; + + a = b + c; + + a.print(); + + Vec3 d; + BOOST_PROTO_AUTO(expr1, b + c); + d = expr1; + d.print(); + + int num = count_leaves(expr1); + std::cout << num << std::endl; + + BOOST_PROTO_AUTO(expr2, b + 3 * c); + num = count_leaves(expr2); + std::cout << num << std::endl; + + BOOST_PROTO_AUTO(expr3, b + c * d); + num = count_leaves(expr3); + std::cout << num << std::endl; + + return 0; +} +//] diff --git a/src/boost/libs/proto/example/vector.cpp b/src/boost/libs/proto/example/vector.cpp new file mode 100644 index 00000000..a2b80fe8 --- /dev/null +++ b/src/boost/libs/proto/example/vector.cpp @@ -0,0 +1,241 @@ +//[ Vector +/////////////////////////////////////////////////////////////////////////////// +// 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) +// +// This is an example of using BOOST_PROTO_DEFINE_OPERATORS to Protofy +// expressions using std::vector<>, a non-proto type. It is a port of the +// Vector example from PETE (http://www.codesourcery.com/pooma/download.html). + +#include <vector> +#include <iostream> +#include <stdexcept> +#include <boost/mpl/bool.hpp> +#include <boost/proto/core.hpp> +#include <boost/proto/debug.hpp> +#include <boost/proto/context.hpp> +#include <boost/utility/enable_if.hpp> +namespace mpl = boost::mpl; +namespace proto = boost::proto; +using proto::_; + +template<typename Expr> +struct VectorExpr; + +// Here is an evaluation context that indexes into a std::vector +// expression and combines the result. +struct VectorSubscriptCtx +{ + VectorSubscriptCtx(std::size_t i) + : i_(i) + {} + + // Unless this is a vector terminal, use the + // default evaluation context + template<typename Expr, typename EnableIf = void> + struct eval + : proto::default_eval<Expr, VectorSubscriptCtx const> + {}; + + // Index vector terminals with our subscript. + template<typename Expr> + struct eval< + Expr + , typename boost::enable_if< + proto::matches<Expr, proto::terminal<std::vector<_, _> > > + >::type + > + { + typedef typename proto::result_of::value<Expr>::type::value_type result_type; + + result_type operator ()(Expr &expr, VectorSubscriptCtx const &ctx) const + { + return proto::value(expr)[ctx.i_]; + } + }; + + std::size_t i_; +}; + +// Here is an evaluation context that verifies that all the +// vectors in an expression have the same size. +struct VectorSizeCtx +{ + VectorSizeCtx(std::size_t size) + : size_(size) + {} + + // Unless this is a vector terminal, use the + // null evaluation context + template<typename Expr, typename EnableIf = void> + struct eval + : proto::null_eval<Expr, VectorSizeCtx const> + {}; + + // Index array terminals with our subscript. Everything + // else will be handled by the default evaluation context. + template<typename Expr> + struct eval< + Expr + , typename boost::enable_if< + proto::matches<Expr, proto::terminal<std::vector<_, _> > > + >::type + > + { + typedef void result_type; + + result_type operator ()(Expr &expr, VectorSizeCtx const &ctx) const + { + if(ctx.size_ != proto::value(expr).size()) + { + throw std::runtime_error("LHS and RHS are not compatible"); + } + } + }; + + std::size_t size_; +}; + +// A grammar which matches all the assignment operators, +// so we can easily disable them. +struct AssignOps + : proto::switch_<struct AssignOpsCases> +{}; + +// Here are the cases used by the switch_ above. +struct AssignOpsCases +{ + template<typename Tag, int D = 0> struct case_ : proto::not_<_> {}; + + template<int D> struct case_< proto::tag::plus_assign, D > : _ {}; + template<int D> struct case_< proto::tag::minus_assign, D > : _ {}; + template<int D> struct case_< proto::tag::multiplies_assign, D > : _ {}; + template<int D> struct case_< proto::tag::divides_assign, D > : _ {}; + template<int D> struct case_< proto::tag::modulus_assign, D > : _ {}; + template<int D> struct case_< proto::tag::shift_left_assign, D > : _ {}; + template<int D> struct case_< proto::tag::shift_right_assign, D > : _ {}; + template<int D> struct case_< proto::tag::bitwise_and_assign, D > : _ {}; + template<int D> struct case_< proto::tag::bitwise_or_assign, D > : _ {}; + template<int D> struct case_< proto::tag::bitwise_xor_assign, D > : _ {}; +}; + +// A vector grammar is a terminal or some op that is not an +// assignment op. (Assignment will be handled specially.) +struct VectorGrammar + : proto::or_< + proto::terminal<_> + , proto::and_<proto::nary_expr<_, proto::vararg<VectorGrammar> >, proto::not_<AssignOps> > + > +{}; + +// Expressions in the vector domain will be wrapped in VectorExpr<> +// and must conform to the VectorGrammar +struct VectorDomain + : proto::domain<proto::generator<VectorExpr>, VectorGrammar> +{}; + +// Here is VectorExpr, which extends a proto expr type by +// giving it an operator [] which uses the VectorSubscriptCtx +// to evaluate an expression with a given index. +template<typename Expr> +struct VectorExpr + : proto::extends<Expr, VectorExpr<Expr>, VectorDomain> +{ + explicit VectorExpr(Expr const &expr) + : proto::extends<Expr, VectorExpr<Expr>, VectorDomain>(expr) + {} + + // Use the VectorSubscriptCtx to implement subscripting + // of a Vector expression tree. + typename proto::result_of::eval<Expr const, VectorSubscriptCtx const>::type + operator []( std::size_t i ) const + { + VectorSubscriptCtx const ctx(i); + return proto::eval(*this, ctx); + } +}; + +// Define a trait type for detecting vector terminals, to +// be used by the BOOST_PROTO_DEFINE_OPERATORS macro below. +template<typename T> +struct IsVector + : mpl::false_ +{}; + +template<typename T, typename A> +struct IsVector<std::vector<T, A> > + : mpl::true_ +{}; + +namespace VectorOps +{ + // This defines all the overloads to make expressions involving + // std::vector to build expression templates. + BOOST_PROTO_DEFINE_OPERATORS(IsVector, VectorDomain) + + typedef VectorSubscriptCtx const CVectorSubscriptCtx; + + // Assign to a vector from some expression. + template<typename T, typename A, typename Expr> + std::vector<T, A> &assign(std::vector<T, A> &arr, Expr const &expr) + { + VectorSizeCtx const size(arr.size()); + proto::eval(proto::as_expr<VectorDomain>(expr), size); // will throw if the sizes don't match + for(std::size_t i = 0; i < arr.size(); ++i) + { + arr[i] = proto::as_expr<VectorDomain>(expr)[i]; + } + return arr; + } + + // Add-assign to a vector from some expression. + template<typename T, typename A, typename Expr> + std::vector<T, A> &operator +=(std::vector<T, A> &arr, Expr const &expr) + { + VectorSizeCtx const size(arr.size()); + proto::eval(proto::as_expr<VectorDomain>(expr), size); // will throw if the sizes don't match + for(std::size_t i = 0; i < arr.size(); ++i) + { + arr[i] += proto::as_expr<VectorDomain>(expr)[i]; + } + return arr; + } +} + +int main() +{ + using namespace VectorOps; + + int i; + const int n = 10; + std::vector<int> a,b,c,d; + std::vector<double> e(n); + + for (i = 0; i < n; ++i) + { + a.push_back(i); + b.push_back(2*i); + c.push_back(3*i); + d.push_back(i); + } + + VectorOps::assign(b, 2); + VectorOps::assign(d, a + b * c); + a += if_else(d < 30, b, c); + + VectorOps::assign(e, c); + e += e - 4 / (c + 1); + + for (i = 0; i < n; ++i) + { + std::cout + << " a(" << i << ") = " << a[i] + << " b(" << i << ") = " << b[i] + << " c(" << i << ") = " << c[i] + << " d(" << i << ") = " << d[i] + << " e(" << i << ") = " << e[i] + << std::endl; + } +} +//] diff --git a/src/boost/libs/proto/example/virtual_member.cpp b/src/boost/libs/proto/example/virtual_member.cpp new file mode 100644 index 00000000..46183bae --- /dev/null +++ b/src/boost/libs/proto/example/virtual_member.cpp @@ -0,0 +1,306 @@ +//[ VirtualMember +// 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) +// +// This example demonstrates how to use BOOST_PROTO_EXTENDS_MEMBERS() +// to add "virtual" data members to expressions within a domain. For +// instance, with Phoenix you can create a lambda expression such as +// +// if_(_1 > 0)[ std::cout << _2 ].else_[ std::cout << _3 ] +// +// In the above expression, "else_" is a so-called virtual data member +// of the expression "if_(_1 > 0)[ std::cout << _2 ]". This example +// shows how to implement the ".else_" syntax with Proto. +// +// ****WARNING****WARNING****WARNING****WARNING****WARNING****WARNING**** +// * The virtual data member feature is experimental and can change at * +// * any time. Use it at your own risk. * +// ********************************************************************** + +#if defined(_MSC_VER) && _MSC_VER == 1310 +#error "Sorry, this example doesn\'t work with MSVC 7.1" +#endif + +#include <iostream> +#include <boost/config.hpp> +#include <boost/detail/workaround.hpp> +#include <boost/mpl/eval_if.hpp> +#include <boost/mpl/min_max.hpp> +#include <boost/mpl/next_prior.hpp> +#include <boost/fusion/include/at.hpp> +#include <boost/fusion/include/vector.hpp> +#include <boost/typeof/std/ostream.hpp> +#include <boost/proto/proto.hpp> + +namespace mpl = boost::mpl; +namespace proto = boost::proto; +namespace fusion = boost::fusion; +using proto::_; + +namespace mini_lambda +{ + // A callable PolymorphicFunctionObject that wraps + // fusion::at() + struct at : proto::callable + { + template<class Sig> + struct result; + + template<class This, class Vector, class N> + struct result<This(Vector, N)> + : fusion::result_of::at< + typename boost::remove_reference<Vector>::type + , typename boost::remove_reference<N>::type + > + {}; + + template<class Vector, class N> + typename fusion::result_of::at<Vector const, N>::type + operator()(Vector const &vector, N) const + { + return fusion::at<N>(vector); + } + }; + + // An MPL IntegralConstant + template<class N> + struct placeholder + { + typedef N type; + typedef typename N::tag tag; + typedef typename N::next next; + typedef typename N::prior prior; + typedef typename N::value_type value_type; + static const value_type value = N::value; + }; + + // Some keyword types for our lambda EDSL + namespace keyword + { + struct if_ {}; + struct else_ {}; + struct do_ {}; + struct while_ {}; + struct try_ {}; + struct catch_ {}; + } + + // Forward declaration for the mini-lambda grammar + struct eval_if_else; + + // Forward declaration for the mini-lambda expression wrapper + template<class E> + struct expression; + + // The grammar for mini-lambda expressions with transforms for + // evaluating the lambda expression. + struct grammar + : proto::or_< + // When evaluating a placeholder, use the placeholder + // to index into the "data" parameter, which is a fusion + // vector containing the arguments to the lambda expression. + proto::when< + proto::terminal<placeholder<_> > + , at(proto::_data, proto::_value) + > + // When evaluating if/then/else expressions of the form + // "if_( E0 )[ E1 ].else_[ E2 ]", pass E0, E1 and E2 to + // eval_if_else along with the "data" parameter. Note the + // use of proto::member<> to match binary expressions like + // "X.Y" where "Y" is a virtual data member. + , proto::when< + proto::subscript< + proto::member< + proto::subscript< + proto::function< + proto::terminal<keyword::if_> + , grammar + > + , grammar + > + , proto::terminal<keyword::else_> + > + , grammar + > + , eval_if_else( + proto::_right(proto::_left(proto::_left(proto::_left))) + , proto::_right(proto::_left(proto::_left)) + , proto::_right + , proto::_data + ) + > + , proto::otherwise< + proto::_default<grammar> + > + > + {}; + + // A callable PolymorphicFunctionObject that evaluates + // if/then/else expressions. + struct eval_if_else : proto::callable + { + typedef void result_type; + + template<typename If, typename Then, typename Else, typename Args> + void operator()(If const &if_, Then const &then_, Else const &else_, Args const &args) const + { + if(grammar()(if_, 0, args)) + { + grammar()(then_, 0, args); + } + else + { + grammar()(else_, 0, args); + } + } + }; + + // Define the mini-lambda domain, in which all expressions are + // wrapped in mini_lambda::expression. + struct domain + : proto::domain<proto::pod_generator<expression> > + {}; + + // A simple transform for computing the arity of + // a lambda expression. + struct arity_of + : proto::or_< + proto::when< + proto::terminal< placeholder<_> > + , mpl::next<proto::_value>() + > + , proto::when< + proto::terminal<_> + , mpl::int_<0>() + > + , proto::otherwise< + proto::fold< + _ + , mpl::int_<0>() + , mpl::max<arity_of, proto::_state>() + > + > + > + {}; + + // Here is the mini-lambda expression wrapper. It serves two purposes: + // 1) To define operator() overloads that evaluate the lambda expression, and + // 2) To define virtual data members like "else_" so that we can write + // expressions like "if_(X)[Y].else_[Z]". + template<class E> + struct expression + { + BOOST_PROTO_BASIC_EXTENDS(E, expression<E>, domain) + BOOST_PROTO_EXTENDS_ASSIGN() + BOOST_PROTO_EXTENDS_SUBSCRIPT() + + // Use BOOST_PROTO_EXTENDS_MEMBERS() to define "virtual" + // data members that all expressions in the mini-lambda + // domain will have. They can be used to create expressions + // like "if_(x)[y].else_[z]" and "do_[y].while_(z)". + BOOST_PROTO_EXTENDS_MEMBERS( + ((keyword::else_, else_)) + ((keyword::while_, while_)) + ((keyword::catch_, catch_)) + ) + + // Calculate the arity of this lambda expression + static int const arity = boost::result_of<arity_of(E)>::type::value; + + // Define overloads of operator() that evaluate the lambda + // expression for up to 3 arguments. + + // Don't try to compute the return type of the lambda if + // it isn't nullary. + typename mpl::eval_if_c< + 0 != arity + , mpl::identity<void> + , boost::result_of<grammar( + E const & + , int const & + , fusion::vector<> & + )> + >::type + operator()() const + { + BOOST_MPL_ASSERT_RELATION(arity, ==, 0); + fusion::vector<> args; + return grammar()(proto_base(), 0, args); + } + + #define BOOST_PROTO_LOCAL_MACRO( \ + N, typename_A, A_const_ref, A_const_ref_a, a \ + ) \ + template<typename_A(N)> \ + typename boost::result_of<grammar( \ + E const & \ + , int const & \ + , fusion::vector<A_const_ref(N)> & \ + )>::type \ + operator ()(A_const_ref_a(N)) const \ + { \ + BOOST_MPL_ASSERT_RELATION(arity, <=, N); \ + fusion::vector<A_const_ref(N)> args(a(N)); \ + return grammar()(proto_base(), 0, args); \ + } + // Repeats BOOST_PROTO_LOCAL_MACRO macro for N=1 to 3 + // inclusive (because there are only 3 placeholders) + #define BOOST_PROTO_LOCAL_a BOOST_PROTO_a + #define BOOST_PROTO_LOCAL_LIMITS (1, 3) + #include BOOST_PROTO_LOCAL_ITERATE() + }; + + namespace placeholders + { + typedef placeholder<mpl::int_<0> > _1_t; + typedef placeholder<mpl::int_<1> > _2_t; + typedef placeholder<mpl::int_<2> > _3_t; + + // Define some placeholders + expression<proto::terminal<_1_t>::type> const _1 = {{{}}}; + expression<proto::terminal<_2_t>::type> const _2 = {{{}}}; + expression<proto::terminal<_3_t>::type> const _3 = {{{}}}; + + // Define the if_() statement + template<typename E> + typename proto::result_of::make_expr<proto::tag::function, domain + , keyword::if_ + , E const & + >::type const + if_(E const &e) + { + return proto::make_expr<proto::tag::function, domain>( + keyword::if_() + , boost::ref(e) + ); + } + } + + using placeholders::if_; +} + +int main() +{ + using namespace mini_lambda::placeholders; + + // OK, we can create if/then/else lambda expressions + // and evaluate them. + if_(_1 > 0) + [ + std::cout << _2 << '\n' + ] + .else_ + [ + std::cout << _3 << '\n' + ] + (-42, "positive", "non-positive"); + + // Even though all expressions in the mini-lambda + // domain have members named else_, while_, and catch_, + // they all occupy the same byte in the expression. + BOOST_MPL_ASSERT_RELATION(sizeof(_1), ==, 2); + + return 0; +} +//] diff --git a/src/boost/libs/proto/index.html b/src/boost/libs/proto/index.html new file mode 100644 index 00000000..2629a3c3 --- /dev/null +++ b/src/boost/libs/proto/index.html @@ -0,0 +1,15 @@ +<html> +<head> +<meta http-equiv="refresh" content="0; URL=../../doc/html/proto.html"> +</head> +<body> +Automatic redirection failed, please go to +<a href="../../doc/html/proto.html">../../doc/html/proto.html</a> +<p>Copyright Eric Niebler 2006</p> +<p>Distributed under the Boost Software License, Version 1.0. (See accompanying file +<a href="../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or copy at +<a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a>). +</p> +</body> +</html> + diff --git a/src/boost/libs/proto/meta/libraries.json b/src/boost/libs/proto/meta/libraries.json new file mode 100644 index 00000000..11ccc12d --- /dev/null +++ b/src/boost/libs/proto/meta/libraries.json @@ -0,0 +1,14 @@ +{ + "key": "proto", + "name": "Proto", + "authors": [ + "Eric Niebler" + ], + "description": "Expression template library and compiler construction toolkit for domain-specific embedded languages.", + "category": [ + "Metaprogramming" + ], + "maintainers": [ + "Eric Niebler <eric -at- boostpro.com>" + ] +} diff --git a/src/boost/libs/proto/preprocess/Jamfile.v2 b/src/boost/libs/proto/preprocess/Jamfile.v2 new file mode 100644 index 00000000..04b7cce0 --- /dev/null +++ b/src/boost/libs/proto/preprocess/Jamfile.v2 @@ -0,0 +1,18 @@ +# (C) Copyright 2012: 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) + +# Generates preprocessed files with wave. + +project : requirements <link>static <variant>release ; + +actions wave +{ + $(>[2]) -o- -DBOOST_PROTO_MAX_ARITY=10 --config-file wave.cfg $(>[1]) +} + +W = /boost/libs/wave/tool//wave ; + +make preprocess_proto + : preprocess_proto.cpp $(W) : wave : <dependency>wave.cfg + ; diff --git a/src/boost/libs/proto/preprocess/preprocess_proto.cpp b/src/boost/libs/proto/preprocess/preprocess_proto.cpp new file mode 100644 index 00000000..b1023f0d --- /dev/null +++ b/src/boost/libs/proto/preprocess/preprocess_proto.cpp @@ -0,0 +1,10 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright 2011 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 "../include/boost/proto/core.hpp" +#include "../include/boost/proto/debug.hpp" +#include "../include/boost/proto/context.hpp" +#include "../include/boost/proto/transform.hpp" +#include "../include/boost/proto/functional.hpp" diff --git a/src/boost/libs/proto/preprocess/wave.cfg b/src/boost/libs/proto/preprocess/wave.cfg new file mode 100644 index 00000000..b0059003 --- /dev/null +++ b/src/boost/libs/proto/preprocess/wave.cfg @@ -0,0 +1,27 @@ +# (C) Copyright 2012: 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) + +# NOTE: Some of the paths in this file may need to be changed for your system. + +-DBOOST_PROTO_DONT_USE_PREPROCESSED_FILES +-DBOOST_PROTO_CREATE_PREPROCESSED_FILES +-D_WIN32 +-NBOOST_STATIC_ASSERT +-NBOOST_PROTO_TEMPLATE_ARITY_PARAM +-NBOOST_PROTO_RESULT_OF +-NBOOST_PROTO_DISABLE_IF_IS_CONST +-NBOOST_PROTO_DISABLE_IF_IS_FUNCTION +-NBOOST_PROTO_USE_GET_POINTER +-NBOOST_PROTO_GET_POINTER +-NBOOST_PROTO_ASSERT_VALID_DOMAIN +-NBOOST_PROTO_RETURN_TYPE_STRICT_LOOSE +-NBOOST_FORCEINLINE +-NBOOST_MPL_ASSERT +-NBOOST_MPL_ASSERT_MSG +-NBOOST_MPL_ASSERT_RELATION +-S../include +-S../../.. +-S"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include" +-S. +--variadics diff --git a/src/boost/libs/proto/test/Jamfile.v2 b/src/boost/libs/proto/test/Jamfile.v2 new file mode 100644 index 00000000..d765eae9 --- /dev/null +++ b/src/boost/libs/proto/test/Jamfile.v2 @@ -0,0 +1,50 @@ +# (C) Copyright 2004: 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) + +# bring in rules for testing +import testing ; + +project + : requirements + <toolset>intel:<debug-symbols>off + <toolset>msvc-7.1:<debug-symbols>off + <toolset>msvc-8.0:<define>_SCL_SECURE_NO_DEPRECATE + <toolset>msvc-8.0:<define>_CRT_SECURE_NO_DEPRECATE + <toolset>msvc-9.0:<define>_SCL_SECURE_NO_DEPRECATE + <toolset>msvc-10.0:<define>_SCL_SECURE_NO_DEPRECATE + <toolset>msvc-11.0:<define>_SCL_SECURE_NO_DEPRECATE + <toolset>msvc-11.0:<define>_SCL_SECURE_NO_WARNINGS + <toolset>gcc:<cxxflags>-ftemplate-depth-1024 + <library>/boost/test//boost_unit_test_framework + <link>static +# <define>BOOST_PROTO_DONT_USE_PREPROCESSED_FILES + ; + +test-suite "proto" + : + [ run calculator.cpp ] + [ run constrained_ops.cpp ] + [ run cpp-next_bug.cpp ] + [ run deep_copy.cpp ] + [ run display_expr.cpp ] + [ run deduce_domain.cpp ] + [ run env_var.cpp ] + [ run examples.cpp ] + [ run external_transforms.cpp ] + [ run lambda.cpp ] + [ run make_expr.cpp ] + [ run matches.cpp ] + [ run flatten.cpp ] + [ run switch.cpp ] + [ run toy_spirit.cpp ] + [ run toy_spirit2.cpp ] + [ run make.cpp ] + [ run mem_ptr.cpp : : : <toolset>msvc:<cxxflags>/wd4355 ] + [ run mpl.cpp ] + [ run noinvoke.cpp ] + [ run pack_expansion.cpp ] + [ run protect.cpp ] + [ compile bug2407.cpp ] + ; + diff --git a/src/boost/libs/proto/test/bug2407.cpp b/src/boost/libs/proto/test/bug2407.cpp new file mode 100644 index 00000000..c67bd55c --- /dev/null +++ b/src/boost/libs/proto/test/bug2407.cpp @@ -0,0 +1,51 @@ +/////////////////////////////////////////////////////////////////////////////// +// bug2407.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/proto/proto.hpp> + +namespace mpl = boost::mpl; +namespace proto = boost::proto; +using proto::_; + +template<class E> +struct e; + +struct g + : proto::or_< + proto::terminal<int> + , proto::plus<g,g> + > +{}; + +struct d + : proto::domain<proto::generator<e>, g> +{}; + +template<class E> +struct e + : proto::extends<E, e<E>, d> +{ + BOOST_MPL_ASSERT((proto::matches<E, g>)); + + e(E const &x = E()) + : proto::extends<E, e<E>, d>(x) + {} +}; + +e<proto::terminal<int>::type> i; + +template<class E> +std::ostream &operator<<(std::ostream &sout, e<E> const &x) +{ + return sout; +} + +int main() +{ + std::cout << (i+i); +} diff --git a/src/boost/libs/proto/test/calculator.cpp b/src/boost/libs/proto/test/calculator.cpp new file mode 100644 index 00000000..ceea6c72 --- /dev/null +++ b/src/boost/libs/proto/test/calculator.cpp @@ -0,0 +1,109 @@ +/////////////////////////////////////////////////////////////////////////////// +// calculator.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 <boost/proto/core.hpp> +#include <boost/proto/context.hpp> +#include <boost/test/unit_test.hpp> + +using namespace boost; + +struct placeholder {}; +proto::terminal<placeholder>::type const _1 = {{}}; + +struct calculator : proto::callable_context<calculator const> +{ + typedef int result_type; + + calculator(int i) + : i_(i) + {} + + int operator ()(proto::tag::terminal, placeholder) const + { + return this->i_; + } + + int operator ()(proto::tag::terminal, int j) const + { + return j; + } + + template<typename Left, typename Right> + int operator ()(proto::tag::plus, Left const &left, Right const &right) const + { + return proto::eval(left, *this) + proto::eval(right, *this); + } + + template<typename Left, typename Right> + int operator ()(proto::tag::minus, Left const &left, Right const &right) const + { + return proto::eval(left, *this) - proto::eval(right, *this); + } + + template<typename Left, typename Right> + int operator ()(proto::tag::multiplies, Left const &left, Right const &right) const + { + return proto::eval(left, *this) * proto::eval(right, *this); + } + + template<typename Left, typename Right> + int operator ()(proto::tag::divides, Left const &left, Right const &right) const + { + return proto::eval(left, *this) / proto::eval(right, *this); + } + +private: + int i_; +}; + +template<typename Fun, typename Expr> +struct functional +{ + typedef typename proto::result_of::eval<Expr, Fun>::type result_type; + + functional(Expr const &expr) + : expr_(expr) + {} + + template<typename T> + result_type operator ()(T const &t) const + { + Fun fun(t); + return proto::eval(this->expr_, fun); + } + +private: + Expr const &expr_; +}; + +template<typename Fun, typename Expr> +functional<Fun, Expr> as(Expr const &expr) +{ + return functional<Fun, Expr>(expr); +} + +void test_calculator() +{ + BOOST_CHECK_EQUAL(10, proto::eval(((_1 + 42)-3)/4, calculator(1))); + BOOST_CHECK_EQUAL(11, proto::eval(((_1 + 42)-3)/4, calculator(5))); + + BOOST_CHECK_EQUAL(10, as<calculator>(((_1 + 42)-3)/4)(1)); + BOOST_CHECK_EQUAL(11, as<calculator>(((_1 + 42)-3)/4)(5)); +} + +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 immediate evaluation of proto parse trees"); + + test->add(BOOST_TEST_CASE(&test_calculator)); + + return test; +} diff --git a/src/boost/libs/proto/test/constrained_ops.cpp b/src/boost/libs/proto/test/constrained_ops.cpp new file mode 100644 index 00000000..c638ddc3 --- /dev/null +++ b/src/boost/libs/proto/test/constrained_ops.cpp @@ -0,0 +1,131 @@ +/////////////////////////////////////////////////////////////////////////////// +// constrained_ops.cpp +// +// Copyright 2010 Thomas Heller +// Copyright 2011 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 <boost/proto/proto.hpp> +#include <boost/test/unit_test.hpp> + +using namespace boost; + +typedef proto::terminal<int>::type term; + +struct equation; + +struct addition: + proto::or_ + < + proto::terminal<proto::_>, + proto::plus<addition, addition> + > +{}; + +struct equation: + proto::or_ + < + proto::equal_to<addition, addition> + > +{}; + +template<class Expr> +struct extension; + +struct my_domain: + proto::domain + < + proto::pod_generator<extension>, + equation, + proto::default_domain + > +{}; + +template<class Expr> +struct lhs_extension; + +struct my_lhs_domain: + proto::domain + < + proto::pod_generator<lhs_extension>, + addition, + my_domain + > +{}; + +template<class Expr> +struct rhs_extension; + +struct my_rhs_domain: + proto::domain + < + proto::pod_generator<rhs_extension>, + addition, + my_domain + > +{}; + +template<class Expr> +struct extension +{ + BOOST_PROTO_BASIC_EXTENDS( + Expr + , extension<Expr> + , my_domain + ) + + void test() const + {} +}; + +template<class Expr> +struct lhs_extension +{ + BOOST_PROTO_BASIC_EXTENDS( + Expr + , lhs_extension<Expr> + , my_lhs_domain + ) +}; + +template<class Expr> +struct rhs_extension +{ + BOOST_PROTO_BASIC_EXTENDS( + Expr + , rhs_extension<Expr> + , my_rhs_domain + ) +}; + +void test_constrained_ops() +{ + lhs_extension<term> const i = {}; + rhs_extension<term> const j = {}; + + proto::assert_matches_not<equation>(i); // false + proto::assert_matches_not<equation>(j); // false + proto::assert_matches_not<equation>(i + i); // false + proto::assert_matches_not<equation>(j + j); // false +#if 0 + proto::assert_matches_not<equation>(i + j); // compile error (by design) + proto::assert_matches_not<equation>(j + i); // compile error (by design) +#endif + proto::assert_matches<equation>(i == j); // true + proto::assert_matches<equation>(i == j + j); // true + proto::assert_matches<equation>(i + i == j); // true + proto::assert_matches<equation>(i + i == j + j); // true +} + +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 constrained EDSLs"); + test->add(BOOST_TEST_CASE(&test_constrained_ops)); + return test; +} diff --git a/src/boost/libs/proto/test/cpp-next_bug.cpp b/src/boost/libs/proto/test/cpp-next_bug.cpp new file mode 100644 index 00000000..2f4b8b47 --- /dev/null +++ b/src/boost/libs/proto/test/cpp-next_bug.cpp @@ -0,0 +1,80 @@ +/////////////////////////////////////////////////////////////////////////////// +// cpp-next_bug.hpp +// +// Copyright 2012 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 <vector> +#include <boost/proto/proto.hpp> +#include <boost/test/unit_test.hpp> +namespace mpl = boost::mpl; +namespace proto = boost::proto; +using proto::_; + +namespace linear_algebra +{ + // A trait that returns true only for std::vector + template<typename T> + struct is_std_vector + : mpl::false_ + {}; + + template<typename T, typename A> + struct is_std_vector<std::vector<T, A> > + : mpl::true_ + {}; + + // A type used as a domain for linear algebra expressions + struct linear_algebra_domain + : proto::domain<> + {}; + + // Define all the operator overloads for combining std::vectors + BOOST_PROTO_DEFINE_OPERATORS(is_std_vector, linear_algebra_domain) + + // Take any expression and turn each node + // into a subscript expression, using the + // state as the RHS. + struct Distribute + : proto::or_< + proto::when<proto::terminal<_>, proto::_make_subscript(_, proto::_state)> + , proto::plus<Distribute, Distribute> + > + {}; + + struct Optimize + : proto::or_< + proto::when< + proto::subscript<Distribute, proto::terminal<_> >, + Distribute(proto::_left, proto::_right) + > + , proto::plus<Optimize, Optimize> + , proto::terminal<_> + > + {}; +} + +static const int celems = 4; +static int const value[celems] = {1,2,3,4}; +std::vector<int> A(value, value+celems), B(A); + +void test1() +{ + using namespace linear_algebra; + proto::_default<> eval; + BOOST_CHECK_EQUAL(8, eval(Optimize()((A + B)[3]))); +} + +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 for a problem reported on the cpp-next.com blog"); + + test->add(BOOST_TEST_CASE(&test1)); + + return test; +} diff --git a/src/boost/libs/proto/test/deduce_domain.cpp b/src/boost/libs/proto/test/deduce_domain.cpp new file mode 100644 index 00000000..47215fdc --- /dev/null +++ b/src/boost/libs/proto/test/deduce_domain.cpp @@ -0,0 +1,142 @@ +/////////////////////////////////////////////////////////////////////////////// +// deduce_domain.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) + +// Avoid a compile-time check inside the deduce_domain code. +#define BOOST_PROTO_ASSERT_VALID_DOMAIN(DOM) typedef DOM DOM ## _ + +#include <boost/proto/core.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/is_same.hpp> + +namespace proto = boost::proto; +using proto::_; + +struct D0 : proto::domain<> +{ +}; + +struct D1 : proto::domain<proto::default_generator, _, D0> +{ +}; + +struct D2 : proto::domain<proto::default_generator, _, D0> +{ +}; + +struct D3 : proto::domain<> +{ +}; + +struct DD0 : proto::domain<proto::default_generator, _, proto::default_domain> +{ +}; + +struct DD1 : proto::domain<proto::default_generator, _, proto::default_domain> +{ +}; + +struct DD2 : proto::domain<proto::default_generator, _, proto::default_domain> +{ +}; + +struct DD3 : proto::domain<proto::default_generator, _, DD2> +{ +}; + +struct DD4 : proto::domain<proto::default_generator, _, DD2> +{ +}; + +void test1() +{ + using boost::is_same; + + //* + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D0, D0, D0>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<proto::default_domain, D0, D0>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D0, proto::default_domain, D0>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D0, D0, proto::default_domain>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D0, proto::default_domain, proto::default_domain>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<proto::default_domain, D0, proto::default_domain>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<proto::default_domain, proto::default_domain, D0>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<proto::default_domain, proto::default_domain, proto::default_domain>::type, proto::default_domain>)); + + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<DD0, D0, D0>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D0, DD0, D0>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D0, D0, DD0>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D0, DD0, DD0>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<DD0, D0, DD0>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<DD0, DD0, D0>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<proto::default_domain, DD0, DD0>::type, DD0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<DD0, proto::default_domain, DD0>::type, DD0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<DD0, DD0, proto::default_domain>::type, DD0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<proto::default_domain, proto::default_domain, DD0>::type, DD0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<proto::default_domain, DD0, proto::default_domain>::type, DD0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<DD0, DD0, proto::default_domain>::type, DD0>)); + + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D0, D0, D1>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D0, D1, D0>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D0, D1, D1>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D1, D0, D0>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D1, D0, D1>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D1, D1, D0>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D1, D1, D1>::type, D1>)); + + // Very tricky to get right + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D2, D2, D1>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D2, D1, D2>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D2, D1, D1>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D1, D2, D2>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D1, D2, D1>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D1, D1, D2>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D1, D1, D1>::type, D1>)); + + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D3, D0, D0>::type, proto::detail::not_a_domain>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D0, D3, D0>::type, proto::detail::not_a_domain>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D0, D0, D3>::type, proto::detail::not_a_domain>)); + + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D3, D1, D0>::type, proto::detail::not_a_domain>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D3, D0, D1>::type, proto::detail::not_a_domain>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D1, D3, D0>::type, proto::detail::not_a_domain>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D0, D3, D1>::type, proto::detail::not_a_domain>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D0, D1, D3>::type, proto::detail::not_a_domain>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D1, D0, D3>::type, proto::detail::not_a_domain>)); + + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D3, D1, D2>::type, proto::detail::not_a_domain>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D3, D2, D1>::type, proto::detail::not_a_domain>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D1, D3, D2>::type, proto::detail::not_a_domain>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D2, D3, D1>::type, proto::detail::not_a_domain>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D2, D1, D3>::type, proto::detail::not_a_domain>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D1, D2, D3>::type, proto::detail::not_a_domain>)); + + // These should be ambiguous. + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<DD1, DD0, DD0>::type, proto::detail::not_a_domain>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<DD0, DD1, DD0>::type, proto::detail::not_a_domain>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<DD0, DD0, DD1>::type, proto::detail::not_a_domain>)); + + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<DD3, DD2, DD2>::type, DD2>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<DD2, DD3, DD2>::type, DD2>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<DD2, DD2, DD3>::type, DD2>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<DD3, DD4, DD4>::type, DD2>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<DD4, DD3, DD4>::type, DD2>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<DD4, DD4, DD3>::type, DD2>)); + //*/ +} + +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 deducing domains from sub-domains"); + + test->add(BOOST_TEST_CASE(&test1)); + + return test; +} diff --git a/src/boost/libs/proto/test/deep_copy.cpp b/src/boost/libs/proto/test/deep_copy.cpp new file mode 100644 index 00000000..42d75282 --- /dev/null +++ b/src/boost/libs/proto/test/deep_copy.cpp @@ -0,0 +1,56 @@ +/////////////////////////////////////////////////////////////////////////////// +// deep_copy.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/utility/addressof.hpp> +#include <boost/proto/core.hpp> +#include <boost/test/unit_test.hpp> + +using namespace boost; + +void foo() {} + +void test1() +{ + using namespace proto; + + int i = 42; + terminal<int &>::type t1 = {i}; + terminal<int>::type r1 = deep_copy(t1); + BOOST_CHECK_EQUAL(42, value(r1)); + + plus<terminal<int>::type, terminal<int>::type>::type r2 = deep_copy(t1 + 24); + BOOST_CHECK_EQUAL(42, value(left(r2))); + BOOST_CHECK_EQUAL(24, value(right(r2))); + + char buf[16] = {'\0'}; + terminal<char (&)[16]>::type t3 = {buf}; + terminal<char[16]>::type r3 = deep_copy(t3); + + terminal<void(&)()>::type t4 = {foo}; + plus<terminal<void(&)()>::type, terminal<int>::type>::type r4 = deep_copy(t4 + t1); + BOOST_CHECK_EQUAL(42, value(right(r4))); + BOOST_CHECK_EQUAL(&foo, &value(left(r4))); + + terminal<std::ostream &>::type cout_ = {std::cout}; + shift_left<terminal<std::ostream &>::type, terminal<int>::type>::type r5 = deep_copy(cout_ << t1); + BOOST_CHECK_EQUAL(42, value(right(r5))); + BOOST_CHECK_EQUAL(boost::addressof(std::cout), boost::addressof(value(left(r5)))); +} + +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 deep_copy of proto parse trees"); + + test->add(BOOST_TEST_CASE(&test1)); + + return test; +} diff --git a/src/boost/libs/proto/test/display_expr.cpp b/src/boost/libs/proto/test/display_expr.cpp new file mode 100644 index 00000000..05c47ff5 --- /dev/null +++ b/src/boost/libs/proto/test/display_expr.cpp @@ -0,0 +1,68 @@ +/////////////////////////////////////////////////////////////////////////////// +// display_expr.cpp +// +// Copyright 2010 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/proto/proto.hpp> +#include <boost/test/unit_test.hpp> + +namespace mpl = boost::mpl; +namespace proto = boost::proto; +using proto::_; + +struct A {}; +struct B : A {}; +std::ostream& operator<<( std::ostream& out, const A& ) { return out << "this is A!"; } + +struct C {}; + +void test_display_expr() +{ + // https://svn.boost.org/trac/boost/ticket/4910 + proto::terminal<int>::type i = {0}; + + { + std::stringstream sout; + proto::display_expr(i + A(), sout); + BOOST_CHECK_EQUAL(sout.str(), std::string( + "plus(\n" + " terminal(0)\n" + " , terminal(this is A!)\n" + ")\n")); + } + + { + std::stringstream sout; + proto::display_expr(i + B(), sout); + BOOST_CHECK_EQUAL(sout.str(), std::string( + "plus(\n" + " terminal(0)\n" + " , terminal(this is A!)\n" + ")\n")); + } + + { + std::stringstream sout; + char const * Cname = BOOST_CORE_TYPEID(C).name(); + proto::display_expr(i + C(), sout); + BOOST_CHECK_EQUAL(sout.str(), std::string( + "plus(\n" + " terminal(0)\n" + " , terminal(") + Cname + std::string(")\n" + ")\n")); + } +} + +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 display_expr() function"); + test->add(BOOST_TEST_CASE(&test_display_expr)); + return test; +} diff --git a/src/boost/libs/proto/test/env_var.cpp b/src/boost/libs/proto/test/env_var.cpp new file mode 100644 index 00000000..14ce8be9 --- /dev/null +++ b/src/boost/libs/proto/test/env_var.cpp @@ -0,0 +1,297 @@ +/////////////////////////////////////////////////////////////////////////////// +// env_var.cpp +// +// Copyright 2012 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 <cstring> +#include <sstream> +#include <boost/config.hpp> +#include <boost/detail/workaround.hpp> +#include <boost/proto/proto.hpp> +#include <boost/test/unit_test.hpp> + +namespace proto = boost::proto; + +BOOST_PROTO_DEFINE_ENV_VAR(tag0_type, tag0); + +struct abstract +{ + virtual ~abstract() = 0; +}; + +abstract::~abstract() {} + +struct concrete : abstract +{ + ~concrete() {} +}; + +template<typename Tag, typename Env> +void assert_has_env_var(Env const &) +{ + BOOST_MPL_ASSERT((proto::result_of::has_env_var<Env, Tag>)); +} + +template<typename Tag, typename Env> +void assert_has_env_var_not(Env const &) +{ + BOOST_MPL_ASSERT_NOT((proto::result_of::has_env_var<Env, Tag>)); +} + +void test_is_env() +{ + BOOST_MPL_ASSERT_NOT((proto::is_env<int>)); + BOOST_MPL_ASSERT_NOT((proto::is_env<int &>)); + BOOST_MPL_ASSERT_NOT((proto::is_env<int const &>)); + + BOOST_MPL_ASSERT_NOT((proto::is_env<abstract>)); + BOOST_MPL_ASSERT_NOT((proto::is_env<abstract &>)); + BOOST_MPL_ASSERT_NOT((proto::is_env<abstract const &>)); + + BOOST_MPL_ASSERT((proto::is_env<proto::empty_env>)); + BOOST_MPL_ASSERT((proto::is_env<proto::empty_env &>)); + BOOST_MPL_ASSERT((proto::is_env<proto::empty_env const &>)); + + BOOST_MPL_ASSERT((proto::is_env<proto::env<tag0_type, int> >)); + BOOST_MPL_ASSERT((proto::is_env<proto::env<tag0_type, int> &>)); + BOOST_MPL_ASSERT((proto::is_env<proto::env<tag0_type, int> const &>)); +} + +void test_as_env() +{ + proto::env<proto::data_type, int> e0 = proto::as_env(2); + BOOST_CHECK_EQUAL(e0[proto::data], 2); + assert_has_env_var<proto::data_type>(e0); + assert_has_env_var_not<tag0_type>(e0); + + int i = 39; + proto::env<proto::data_type, int &> e1 = proto::as_env(boost::ref(i)); + assert_has_env_var<proto::data_type>(i); + assert_has_env_var_not<tag0_type>(i); + BOOST_CHECK_EQUAL(e1[proto::data], 39); + BOOST_CHECK_EQUAL(&e1[proto::data], &i); + + proto::empty_env e2 = proto::as_env(proto::empty_env()); + proto::env<proto::data_type, int &> e3 = proto::as_env(e1); + proto::env<proto::data_type, int &> & e4 = proto::as_env(boost::ref(e1)); + BOOST_CHECK_EQUAL(&e4, &e1); + + concrete c; + abstract &a = c; + std::stringstream sout; + int rgi[2] = {}; + proto::env<proto::data_type, abstract &> e5 = proto::as_env(a); + proto::env<proto::data_type, std::stringstream &> e6 = proto::as_env(sout); + BOOST_CHECK_EQUAL(&e6[proto::data], &sout); + proto::env<proto::data_type, int(&)[2]> e7 = proto::as_env(rgi); + BOOST_CHECK_EQUAL(&e7[proto::data][0], &rgi[0]); + proto::env<proto::data_type, void(&)()> e8 = proto::as_env(test_as_env); + BOOST_CHECK_EQUAL(&e8[proto::data], &test_as_env); +} + +void test_comma() +{ + proto::env<proto::data_type, int> e0 = (proto::data = 1); + BOOST_CHECK_EQUAL(e0[proto::data], 1); + + int i = 39; + proto::env<proto::data_type, int &> e1 = (proto::data = boost::ref(i)); + BOOST_CHECK_EQUAL(e1[proto::data], 39); + BOOST_CHECK_EQUAL(&e1[proto::data], &i); + + concrete c; + abstract &a = c; + std::stringstream sout; + int rgi[2] = {}; + proto::env<proto::data_type, abstract &> e5 = (proto::data = a); + proto::env<proto::data_type, std::stringstream &> e6 = (proto::data = sout); + BOOST_CHECK_EQUAL(&e6[proto::data], &sout); + proto::env<proto::data_type, int(&)[2]> e7 = (proto::data = rgi); + BOOST_CHECK_EQUAL(&e7[proto::data][0], &rgi[0]); + // The test below fails on msvc due to a compiler bug + // note: <https://connect.microsoft.com/VisualStudio/feedback/details/754684/premature-decay-of-function-types-in-overloaded-assignment-operator> +#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) + proto::env<proto::data_type, void(&)()> e8 = (proto::data = boost::ref(test_as_env)); + BOOST_CHECK_EQUAL(&e8[proto::data], &test_as_env); +#else + proto::env<proto::data_type, void(&)()> e8 = (proto::data = test_as_env); + BOOST_CHECK_EQUAL(&e8[proto::data], &test_as_env); +#endif + + proto::env< + tag0_type + , char const (&)[6] + , proto::env<proto::data_type, int> + > e9 = (proto::data = 1, tag0 = "hello"); + BOOST_CHECK_EQUAL(e9[proto::data], 1); + BOOST_CHECK_EQUAL(0, std::strcmp(e9[tag0], "hello")); + + proto::env< + tag0_type + , int + , proto::env< + tag0_type + , char const (&)[6] + , proto::env<proto::data_type, int> + > + > e10 = (proto::data = 1, tag0 = "hello", tag0 = 42); + BOOST_CHECK_EQUAL(e10[proto::data], 1); + BOOST_CHECK_EQUAL(e10[tag0], 42); + + proto::env< + tag0_type + , char const (&)[6] + , proto::env<proto::data_type, abstract &> + > e11 = (a, tag0 = "hello"); + BOOST_CHECK_EQUAL(&e11[proto::data], &a); + BOOST_CHECK_EQUAL(0, std::strcmp(e11[tag0], "hello")); + + proto::env< + tag0_type + , int + , proto::env< + tag0_type + , char const (&)[6] + , proto::env<proto::data_type, abstract &> + > + > e12 = (a, tag0 = "hello", tag0 = 42); + BOOST_CHECK_EQUAL(&e12[proto::data], &a); + BOOST_CHECK_EQUAL(e12[tag0], 42); + + proto::env<tag0_type, int> e13 = (proto::empty_env(), tag0 = 42); + BOOST_CHECK_EQUAL(e13[tag0], 42); + assert_has_env_var<tag0_type>(e13); + assert_has_env_var_not<proto::data_type>(e13); + + proto::empty_env empty; + proto::env<tag0_type, int> e14 = (boost::ref(empty), tag0 = 42); + BOOST_CHECK_EQUAL(e14[tag0], 42); + + proto::env< + proto::data_type + , char const (&)[6] + , proto::env<tag0_type, int> + > e15 = (boost::ref(e14), proto::data = "hello"); + BOOST_CHECK_EQUAL(e15[tag0], 42); + BOOST_CHECK_EQUAL(0, std::strcmp(e15[proto::data], "hello")); + + proto::env< + proto::data_type + , char const (&)[6] + , proto::env<tag0_type, int> + > e16 = (proto::as_env(boost::ref(e14)), proto::data = "hello"); + BOOST_CHECK_EQUAL(e16[tag0], 42); + BOOST_CHECK_EQUAL(0, std::strcmp(e16[proto::data], "hello")); +} + +void test_result_of_env_var() +{ + typedef proto::empty_env env0_type; + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env0_type, proto::data_type>::type, proto::key_not_found>)); + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env0_type &, proto::data_type>::type, proto::key_not_found>)); + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env0_type const &, proto::data_type>::type, proto::key_not_found>)); + + typedef proto::env<proto::data_type, int> env1_type; + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env1_type, proto::data_type>::type, int>)); + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env1_type &, proto::data_type>::type, int>)); + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env1_type const &, proto::data_type>::type, int>)); + + typedef proto::env<proto::data_type, int &> env2_type; + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env2_type, proto::data_type>::type, int &>)); + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env2_type &, proto::data_type>::type, int &>)); + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env2_type const &, proto::data_type>::type, int &>)); + + typedef proto::env<proto::data_type, double, proto::env<tag0_type, abstract &> > env3_type; + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env3_type, proto::data_type>::type, double>)); + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env3_type, tag0_type>::type, abstract &>)); + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env3_type &, proto::data_type>::type, double>)); + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env3_type &, tag0_type>::type, abstract &>)); + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env3_type const &, proto::data_type>::type, double>)); + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env3_type const &, tag0_type>::type, abstract &>)); + + typedef proto::env<tag0_type, double, proto::env<tag0_type, abstract &> > env4_type; + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env4_type, tag0_type>::type, double>)); + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env4_type &, tag0_type>::type, double>)); + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env4_type const &, tag0_type>::type, double>)); +} + +void test_env_var() +{ + proto::key_not_found x0 = proto::env_var<proto::data_type>(proto::empty_env()); + proto::key_not_found x1 = proto::env_var<proto::data_type>(tag0 = 42); + int x2 = proto::env_var<tag0_type>(tag0 = 42); + BOOST_CHECK_EQUAL(x2, 42); + int x3 = proto::functional::env_var<tag0_type>()(tag0 = 42); + BOOST_CHECK_EQUAL(x3, 42); + + int i = 43; + int & x4 = proto::env_var<tag0_type>(tag0 = boost::ref(i)); + BOOST_CHECK_EQUAL(&x4, &i); + int & x5 = proto::functional::env_var<tag0_type>()(tag0 = boost::ref(i)); + BOOST_CHECK_EQUAL(&x5, &i); + + concrete c; + abstract &a = c; + abstract &x6 = proto::env_var<tag0_type>(tag0 = a); + BOOST_CHECK_EQUAL(&x6, &a); + abstract &x7 = proto::functional::env_var<tag0_type>()(tag0 = a); + BOOST_CHECK_EQUAL(&x7, &a); + + abstract &x8 = proto::env_var<tag0_type>((42, tag0 = a)); + BOOST_CHECK_EQUAL(&x8, &a); + abstract &x9 = proto::functional::env_var<tag0_type>()((42, tag0 = a)); + BOOST_CHECK_EQUAL(&x9, &a); +} + +void test_env_var_tfx() +{ + typedef proto::terminal<int>::type int_; + int_ i = {42}; + + // tests for _env + BOOST_MPL_ASSERT((boost::is_same<boost::result_of<proto::_env(int_ &)>::type, proto::empty_env>)); + BOOST_MPL_ASSERT((boost::is_same<boost::result_of<proto::_env(int_ &, int)>::type, proto::empty_env>)); + BOOST_MPL_ASSERT((boost::is_same<boost::result_of<proto::_env(int_ &, int &, float &)>::type, float &>)); + + // Bummer, is there any way around this? +#ifdef BOOST_RESULT_OF_USE_DECLTYPE + BOOST_MPL_ASSERT((boost::is_same<boost::result_of<proto::_env(int_ &, int &, float)>::type, float const &>)); + BOOST_MPL_ASSERT((boost::is_same<boost::tr1_result_of<proto::_env(int_ &, int &, float)>::type, float>)); +#else + BOOST_MPL_ASSERT((boost::is_same<boost::result_of<proto::_env(int_ &, int &, float)>::type, float>)); + BOOST_MPL_ASSERT((boost::is_same<boost::tr1_result_of<proto::_env(int_ &, int &, float)>::type, float>)); +#endif + + double d = 3.14; + double & rd = proto::_env()(i, 0, d); + BOOST_CHECK_EQUAL(&d, &rd); + + proto::env<proto::data_type, int> e0 = proto::_env()(i, 0, proto::as_env(42)); + BOOST_CHECK_EQUAL(e0[proto::data], 42); + + proto::env<proto::data_type, int> e1 = proto::_env()(i, 0, proto::functional::as_env()(42)); + BOOST_CHECK_EQUAL(e1[proto::data], 42); + + proto::env<proto::data_type, int> e2 = proto::_env()(i, 0, (proto::data = 42)); + BOOST_CHECK_EQUAL(e2[proto::data], 42); + + proto::env<proto::data_type, int, proto::env<proto::data_type, int> > e3 = proto::_env()(i, 0, (42, proto::data = 43)); + BOOST_CHECK_EQUAL(e3[proto::data], 43); +} + +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 for environment variables"); + test->add(BOOST_TEST_CASE(&test_as_env)); + test->add(BOOST_TEST_CASE(&test_comma)); + test->add(BOOST_TEST_CASE(&test_result_of_env_var)); + test->add(BOOST_TEST_CASE(&test_env_var)); + test->add(BOOST_TEST_CASE(&test_env_var_tfx)); + return test; +} diff --git a/src/boost/libs/proto/test/examples.cpp b/src/boost/libs/proto/test/examples.cpp new file mode 100644 index 00000000..35769bca --- /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; +} diff --git a/src/boost/libs/proto/test/external_transforms.cpp b/src/boost/libs/proto/test/external_transforms.cpp new file mode 100644 index 00000000..f72e9458 --- /dev/null +++ b/src/boost/libs/proto/test/external_transforms.cpp @@ -0,0 +1,185 @@ +// Copyright 2011 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) +// +// This is an example of how to specify a transform externally so +// that a single grammar can be used to drive multiple differnt +// calculations. In particular, it defines a calculator grammar +// that computes the result of an expression with either checked +// or non-checked division. + +#include <iostream> +#include <boost/mpl/int.hpp> +#include <boost/mpl/next.hpp> +#include <boost/mpl/min_max.hpp> +#include <boost/fusion/container/vector.hpp> +#include <boost/fusion/container/generation/make_vector.hpp> +#include <boost/proto/proto.hpp> +#include <boost/test/unit_test.hpp> + +namespace mpl = boost::mpl; +namespace proto = boost::proto; +namespace fusion = boost::fusion; +using proto::_; + +// The argument placeholder type +template<typename I> struct placeholder : I {}; + +// Give each rule in the grammar a "name". This is so that we +// can easily dispatch on it later. +struct calc_grammar; +struct divides_rule : proto::divides<calc_grammar, calc_grammar> {}; + +// Use external transforms in calc_gramar +struct calc_grammar + : proto::or_< + proto::when< + proto::terminal<placeholder<_> > + , proto::functional::at(proto::_state, proto::_value) + > + , proto::when< + proto::terminal<proto::convertible_to<double> > + , proto::_value + > + , proto::when< + proto::plus<calc_grammar, calc_grammar> + , proto::_default<calc_grammar> + > + , proto::when< + proto::minus<calc_grammar, calc_grammar> + , proto::_default<calc_grammar> + > + , proto::when< + proto::multiplies<calc_grammar, calc_grammar> + , proto::_default<calc_grammar> + > + // Note that we don't specify how division nodes are + // handled here. Proto::external_transform is a placeholder + // for an actual transform. + , proto::when< + divides_rule + , proto::external_transform + > + > +{}; + +template<typename E> struct calc_expr; +struct calc_domain : proto::domain<proto::generator<calc_expr> > {}; + +template<typename E> +struct calc_expr + : proto::extends<E, calc_expr<E>, calc_domain> +{ + calc_expr(E const &e = E()) : calc_expr::proto_extends(e) {} +}; + +calc_expr<proto::terminal<placeholder<mpl::int_<0> > >::type> _1; +calc_expr<proto::terminal<placeholder<mpl::int_<1> > >::type> _2; + +// Use proto::external_transforms to map from named grammar rules to +// transforms. +struct non_checked_division + : proto::external_transforms< + proto::when< divides_rule, proto::_default<calc_grammar> > + > +{}; + +struct division_by_zero : std::exception {}; + +struct do_checked_divide + : proto::callable +{ + typedef int result_type; + int operator()(int left, int right) const + { + if (right == 0) throw division_by_zero(); + return left / right; + } +}; + +// Use proto::external_transforms again, this time to map the divides_rule +// to a transforms that performs checked division. +struct checked_division + : proto::external_transforms< + proto::when< + divides_rule + , do_checked_divide(calc_grammar(proto::_left), calc_grammar(proto::_right)) + > + > +{}; + +BOOST_PROTO_DEFINE_ENV_VAR(mydata_tag, mydata); + +void test_external_transforms() +{ + non_checked_division non_checked; + int result1 = calc_grammar()(_1 / _2, fusion::make_vector(6, 2), non_checked); + BOOST_CHECK_EQUAL(result1, 3); + + // check that additional data slots are ignored + int result2 = calc_grammar()(_1 / _2, fusion::make_vector(8, 2), (non_checked, mydata = "foo")); + BOOST_CHECK_EQUAL(result2, 4); + + // check that we can use the dedicated slot for this purpose + int result3 = calc_grammar()(_1 / _2, fusion::make_vector(8, 2), (42, proto::transforms = non_checked, mydata = "foo")); + BOOST_CHECK_EQUAL(result2, 4); + + checked_division checked; + try + { + // This should throw + int result3 = calc_grammar()(_1 / _2, fusion::make_vector(6, 0), checked); + BOOST_CHECK(!"Didn't throw an exception"); // shouldn't get here! + } + catch(division_by_zero) + { + ; // OK + } + catch(...) + { + BOOST_CHECK(!"Unexpected exception"); // shouldn't get here! + } + + try + { + // This should throw + int result4 = calc_grammar()(_1 / _2, fusion::make_vector(6, 0), (checked, mydata = test_external_transforms)); + BOOST_CHECK(!"Didn't throw an exception"); // shouldn't get here! + } + catch(division_by_zero) + { + ; // OK + } + catch(...) + { + BOOST_CHECK(!"Unexpected exception"); // shouldn't get here! + } + + try + { + // This should throw + int result5 = calc_grammar()(_1 / _2, fusion::make_vector(6, 0), (42, proto::transforms = checked, mydata = test_external_transforms)); + BOOST_CHECK(!"Didn't throw an exception"); // shouldn't get here! + } + catch(division_by_zero) + { + ; // OK + } + catch(...) + { + BOOST_CHECK(!"Unexpected exception"); // shouldn't get here! + } +} + +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 for external transforms"); + + test->add(BOOST_TEST_CASE(&test_external_transforms)); + + return test; +} diff --git a/src/boost/libs/proto/test/flatten.cpp b/src/boost/libs/proto/test/flatten.cpp new file mode 100644 index 00000000..fd19474b --- /dev/null +++ b/src/boost/libs/proto/test/flatten.cpp @@ -0,0 +1,211 @@ +/////////////////////////////////////////////////////////////////////////////// +// proto_fusion_s.cpp +// +// 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 <boost/proto/core.hpp> +#include <boost/proto/fusion.hpp> +#include <boost/fusion/include/for_each.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/utility/addressof.hpp> +#include <sstream> + +std::ostream &operator <<(std::ostream &sout, boost::proto::tag::shift_right) +{ + return sout << ">>"; +} + +std::ostream &operator <<(std::ostream &sout, boost::proto::tag::bitwise_or) +{ + return sout << "|"; +} + +template<typename Args> +std::ostream &operator <<(std::ostream &sout, boost::proto::expr<boost::proto::tag::terminal, Args, 0> const *op) +{ + return sout << boost::proto::value(*op); +} + +template<typename Args> +std::ostream &operator <<(std::ostream &sout, boost::proto::basic_expr<boost::proto::tag::terminal, Args, 0> const *op) +{ + return sout << boost::proto::value(*op); +} + +template<typename Tag, typename Args> +std::ostream &operator <<(std::ostream &sout, boost::proto::expr<Tag, Args, 1> const *op) +{ + return sout << Tag() << boost::addressof(boost::proto::child(*op).proto_base()); +} + +template<typename Tag, typename Args> +std::ostream &operator <<(std::ostream &sout, boost::proto::basic_expr<Tag, Args, 1> const *op) +{ + return sout << Tag() << boost::addressof(boost::proto::child(*op).proto_base()); +} + +template<typename Tag, typename Args> +std::ostream &operator <<(std::ostream &sout, boost::proto::expr<Tag, Args, 2> const *op) +{ + return sout << boost::addressof(boost::proto::left(*op).proto_base()) << Tag() << boost::addressof(boost::proto::right(*op).proto_base()); +} + +template<typename Tag, typename Args> +std::ostream &operator <<(std::ostream &sout, boost::proto::basic_expr<Tag, Args, 2> const *op) +{ + return sout << boost::addressof(boost::proto::left(*op).proto_base()) << Tag() << boost::addressof(boost::proto::right(*op).proto_base()); +} + +/////////////////////////////////////////////////////////////////////////////// +// to_string +// +struct to_string +{ + to_string(std::ostream &sout) + : sout_(sout) + {} + + template<typename Op> + void operator ()(Op const &op) const + { + this->sout_ << '(' << boost::addressof(op.proto_base()) << ')'; + } +private: + std::ostream &sout_; +}; + +void test1() +{ + using boost::proto::flatten; + + boost::proto::terminal<char>::type a_ = {'a'}; + boost::proto::terminal<char>::type b_ = {'b'}; + boost::proto::terminal<char>::type c_ = {'c'}; + boost::proto::terminal<char>::type d_ = {'d'}; + boost::proto::terminal<char>::type e_ = {'e'}; + boost::proto::terminal<char>::type f_ = {'f'}; + boost::proto::terminal<char>::type g_ = {'g'}; + boost::proto::terminal<char>::type h_ = {'h'}; + boost::proto::terminal<char>::type i_ = {'i'}; + + std::stringstream sout; + + // Test for 1-way branching "tree" + sout.str(""); + boost::fusion::for_each(flatten(!!!!(a_ >> b_)), to_string(sout)); + BOOST_CHECK_EQUAL("(a>>b)", sout.str()); + + // Tests for 2-way branching trees + sout.str(""); + boost::fusion::for_each(flatten(a_ >> b_ >> c_), to_string(sout)); + BOOST_CHECK_EQUAL("(a)(b)(c)", sout.str()); + + sout.str(""); + boost::fusion::for_each(flatten(a_ | b_ | c_), to_string(sout)); + BOOST_CHECK_EQUAL("(a)(b)(c)", sout.str()); + + sout.str(""); + boost::fusion::for_each(flatten(a_ >> b_ | c_ >> d_), to_string(sout)); + BOOST_CHECK_EQUAL("(a>>b)(c>>d)", sout.str()); + + sout.str(""); + boost::fusion::for_each(flatten(a_ | b_ >> c_ | d_), to_string(sout)); + BOOST_CHECK_EQUAL("(a)(b>>c)(d)", sout.str()); + + sout.str(""); + boost::fusion::for_each(flatten(a_ >> b_ | c_ >> d_ | e_ >> f_ >> g_), to_string(sout)); + BOOST_CHECK_EQUAL("(a>>b)(c>>d)(e>>f>>g)", sout.str()); + + sout.str(""); + boost::fusion::for_each(flatten(a_ >> b_ | c_ >> d_ | e_ >> (f_ | g_) >> h_), to_string(sout)); + BOOST_CHECK_EQUAL("(a>>b)(c>>d)(e>>f|g>>h)", sout.str()); + + // Test for n-way branching tree + sout.str(""); + boost::fusion::for_each(flatten(a_(b_(c_ >> d_, e_ | f_), g_ >> h_)(i_)), to_string(sout)); + BOOST_CHECK_EQUAL("(a)(b)(c>>d)(e|f)(g>>h)(i)", sout.str()); +} + +//////////////////////////////////////////////////////////////////////// +// Test that EXTENDS expression wrappers are also valid fusion sequences + +template<typename Expr> +struct My; + +struct MyDomain + : boost::proto::domain<boost::proto::pod_generator<My> > +{}; + +template<typename Expr> +struct My +{ + BOOST_PROTO_EXTENDS(Expr, My<Expr>, MyDomain) +}; + +void test2() +{ + using boost::proto::flatten; + + My<boost::proto::terminal<char>::type> a_ = {{'a'}}; + My<boost::proto::terminal<char>::type> b_ = {{'b'}}; + My<boost::proto::terminal<char>::type> c_ = {{'c'}}; + My<boost::proto::terminal<char>::type> d_ = {{'d'}}; + My<boost::proto::terminal<char>::type> e_ = {{'e'}}; + My<boost::proto::terminal<char>::type> f_ = {{'f'}}; + My<boost::proto::terminal<char>::type> g_ = {{'g'}}; + My<boost::proto::terminal<char>::type> h_ = {{'h'}}; + My<boost::proto::terminal<char>::type> i_ = {{'i'}}; + + std::stringstream sout; + + // Test for 1-way branching "tree" + sout.str(""); + boost::fusion::for_each(flatten(!!!!(a_ >> b_)), to_string(sout)); + BOOST_CHECK_EQUAL("(a>>b)", sout.str()); + + // Tests for 2-way branching trees + sout.str(""); + boost::fusion::for_each(flatten(a_ >> b_ >> c_), to_string(sout)); + BOOST_CHECK_EQUAL("(a)(b)(c)", sout.str()); + + sout.str(""); + boost::fusion::for_each(flatten(a_ | b_ | c_), to_string(sout)); + BOOST_CHECK_EQUAL("(a)(b)(c)", sout.str()); + + sout.str(""); + boost::fusion::for_each(flatten(a_ >> b_ | c_ >> d_), to_string(sout)); + BOOST_CHECK_EQUAL("(a>>b)(c>>d)", sout.str()); + + sout.str(""); + boost::fusion::for_each(flatten(a_ | b_ >> c_ | d_), to_string(sout)); + BOOST_CHECK_EQUAL("(a)(b>>c)(d)", sout.str()); + + sout.str(""); + boost::fusion::for_each(flatten(a_ >> b_ | c_ >> d_ | e_ >> f_ >> g_), to_string(sout)); + BOOST_CHECK_EQUAL("(a>>b)(c>>d)(e>>f>>g)", sout.str()); + + sout.str(""); + boost::fusion::for_each(flatten(a_ >> b_ | c_ >> d_ | e_ >> (f_ | g_) >> h_), to_string(sout)); + BOOST_CHECK_EQUAL("(a>>b)(c>>d)(e>>f|g>>h)", sout.str()); + + // Test for n-way branching tree + sout.str(""); + boost::fusion::for_each(flatten(a_(b_(c_ >> d_, e_ | f_), g_ >> h_)(i_)), to_string(sout)); + BOOST_CHECK_EQUAL("(a)(b)(c>>d)(e|f)(g>>h)(i)", sout.str()); +} + +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 proto and segmented fusion integration"); + + test->add(BOOST_TEST_CASE(&test1)); + test->add(BOOST_TEST_CASE(&test2)); + + return test; +} 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; +} diff --git a/src/boost/libs/proto/test/make.cpp b/src/boost/libs/proto/test/make.cpp new file mode 100644 index 00000000..17675aa2 --- /dev/null +++ b/src/boost/libs/proto/test/make.cpp @@ -0,0 +1,98 @@ +/////////////////////////////////////////////////////////////////////////////// +// make.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 <boost/proto/core.hpp> +#include <boost/proto/transform/arg.hpp> +#include <boost/proto/transform/make.hpp> +#include <boost/mpl/identity.hpp> +#include <boost/test/unit_test.hpp> + +namespace mpl = boost::mpl; +namespace proto = boost::proto; +using proto::_; + +template<typename T> +struct type2type {}; + +template<typename T> +struct wrapper +{ + T t_; + explicit wrapper(T const & t = T()) : t_(t) {} +}; + +template<typename T> +struct careful +{ + typedef typename T::not_there not_there; +}; + +// Test that when no substitution is done, we don't instantiate templates +struct MakeTest1 + : proto::make< type2type< careful<int> > > +{}; + +void make_test1() +{ + proto::terminal<int>::type i = {42}; + type2type< careful<int> > res = MakeTest1()(i); +} + +// Test that when substitution is done, and there is no nested ::type +// typedef, the result is the wrapper +struct MakeTest2 + : proto::make< wrapper< proto::_value > > +{}; + +void make_test2() +{ + proto::terminal<int>::type i = {42}; + wrapper<int> res = MakeTest2()(i); + BOOST_CHECK_EQUAL(res.t_, 0); +} + +// Test that when substitution is done, and there is no nested ::type +// typedef, the result is the wrapper +struct MakeTest3 + : proto::make< wrapper< proto::_value >(proto::_value) > +{}; + +void make_test3() +{ + proto::terminal<int>::type i = {42}; + wrapper<int> res = MakeTest3()(i); + BOOST_CHECK_EQUAL(res.t_, 42); +} + +// Test that when substitution is done, and there is no nested ::type +// typedef, the result is the wrapper +struct MakeTest4 + : proto::make< mpl::identity< proto::_value >(proto::_value) > +{}; + +void make_test4() +{ + proto::terminal<int>::type i = {42}; + int res = MakeTest4()(i); + BOOST_CHECK_EQUAL(res, 42); +} + +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 the make transform"); + + test->add(BOOST_TEST_CASE(&make_test1)); + test->add(BOOST_TEST_CASE(&make_test2)); + test->add(BOOST_TEST_CASE(&make_test3)); + test->add(BOOST_TEST_CASE(&make_test4)); + + return test; +} diff --git a/src/boost/libs/proto/test/make_expr.cpp b/src/boost/libs/proto/test/make_expr.cpp new file mode 100644 index 00000000..d59f7574 --- /dev/null +++ b/src/boost/libs/proto/test/make_expr.cpp @@ -0,0 +1,407 @@ +/////////////////////////////////////////////////////////////////////////////// +// proto::make_expr.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/proto/core.hpp> +#include <boost/proto/transform.hpp> +#include <boost/utility/addressof.hpp> +#include <boost/fusion/tuple.hpp> +#include <boost/test/unit_test.hpp> + +namespace fusion = boost::fusion; +namespace proto = boost::proto; + +template<typename E> struct ewrap; + +struct mydomain + : proto::domain<proto::generator<ewrap> > +{}; + +template<typename E> struct ewrap + : proto::extends<E, ewrap<E>, mydomain> +{ + explicit ewrap(E const &e = E()) + : proto::extends<E, ewrap<E>, mydomain>(e) + {} +}; + +void test_make_expr() +{ + int i = 42; + proto::terminal<int>::type t1 = proto::make_expr<proto::tag::terminal>(1); + proto::terminal<int>::type t2 = proto::make_expr<proto::tag::terminal>(i); + proto::unary_plus<proto::terminal<int>::type>::type p1 = proto::make_expr<proto::tag::unary_plus>(1); + proto::unary_plus<proto::terminal<int>::type>::type p2 = proto::make_expr<proto::tag::unary_plus>(i); + BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42); + + typedef + ewrap< + proto::basic_expr< + proto::tag::unary_plus + , proto::list1< + ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > > + > + > + > + p3_type; + p3_type p3 = proto::make_expr<proto::tag::unary_plus, mydomain>(i); + BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42); + + typedef + ewrap< + proto::basic_expr< + proto::tag::plus + , proto::list2< + p3_type + , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > > + > + > + > + p4_type; + p4_type p4 = proto::make_expr<proto::tag::plus>(p3, 0); + BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42); +} + +void test_make_expr_ref() +{ + int i = 42; + int const ci = 84; + proto::terminal<int const &>::type t1 = proto::make_expr<proto::tag::terminal>(boost::cref(ci)); + proto::terminal<int &>::type t2 = proto::make_expr<proto::tag::terminal>(boost::ref(i)); + BOOST_CHECK_EQUAL(&i, &proto::value(t2)); + proto::unary_plus<proto::terminal<int const &>::type>::type p1 = proto::make_expr<proto::tag::unary_plus>(boost::cref(ci)); + proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::make_expr<proto::tag::unary_plus>(boost::ref(i)); + BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42); + + typedef + ewrap< + proto::basic_expr< + proto::tag::unary_plus + , proto::list1< + ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int &> > > + > + > + > + p3_type; + p3_type p3 = proto::make_expr<proto::tag::unary_plus, mydomain>(boost::ref(i)); + BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42); + + typedef + ewrap< + proto::basic_expr< + proto::tag::plus + , proto::list2< + p3_type & + , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > > + > + > + > + p4_type; + p4_type p4 = proto::make_expr<proto::tag::plus>(boost::ref(p3), 0); + BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42); +} + +void test_make_expr_functional() +{ + int i = 42; + proto::terminal<int>::type t1 = proto::functional::make_expr<proto::tag::terminal>()(1); + proto::terminal<int>::type t2 = proto::functional::make_expr<proto::tag::terminal>()(i); + proto::unary_plus<proto::terminal<int>::type>::type p1 = proto::functional::make_expr<proto::tag::unary_plus>()(1); + proto::unary_plus<proto::terminal<int>::type>::type p2 = proto::functional::make_expr<proto::tag::unary_plus>()(i); + BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42); + + typedef + ewrap< + proto::basic_expr< + proto::tag::unary_plus + , proto::list1< + ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > > + > + > + > + p3_type; + p3_type p3 = proto::functional::make_expr<proto::tag::unary_plus, mydomain>()(i); + BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42); + + typedef + ewrap< + proto::basic_expr< + proto::tag::plus + , proto::list2< + p3_type + , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > > + > + > + > + p4_type; + p4_type p4 = proto::functional::make_expr<proto::tag::plus>()(p3, 0); +} + +void test_make_expr_functional_ref() +{ + int i = 42; + int const ci = 84; + proto::terminal<int const &>::type t1 = proto::functional::make_expr<proto::tag::terminal>()(boost::cref(ci)); + proto::terminal<int &>::type t2 = proto::functional::make_expr<proto::tag::terminal>()(boost::ref(i)); + BOOST_CHECK_EQUAL(&i, &proto::value(t2)); + proto::unary_plus<proto::terminal<int const &>::type>::type p1 = proto::functional::make_expr<proto::tag::unary_plus>()(boost::cref(ci)); + proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::functional::make_expr<proto::tag::unary_plus>()(boost::ref(i)); + BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42); + + typedef + ewrap< + proto::basic_expr< + proto::tag::unary_plus + , proto::list1< + ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int &> > > + > + > + > + p3_type; + p3_type p3 = proto::functional::make_expr<proto::tag::unary_plus, mydomain>()(boost::ref(i)); + BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42); + + typedef + ewrap< + proto::basic_expr< + proto::tag::plus + , proto::list2< + p3_type & + , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > > + > + > + > + p4_type; + p4_type p4 = proto::functional::make_expr<proto::tag::plus>()(boost::ref(p3), 0); + BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42); +} + +void test_unpack_expr() +{ + int i = 42; + proto::terminal<int>::type t1 = proto::unpack_expr<proto::tag::terminal>(fusion::make_tuple(1)); + proto::terminal<int &>::type t2 = proto::unpack_expr<proto::tag::terminal>(fusion::make_tuple(boost::ref(i))); + proto::unary_plus<proto::terminal<int>::type>::type p1 = proto::unpack_expr<proto::tag::unary_plus>(fusion::make_tuple(1)); + proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::unpack_expr<proto::tag::unary_plus>(fusion::make_tuple(boost::ref(i))); + BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42); + + typedef + ewrap< + proto::basic_expr< + proto::tag::unary_plus + , proto::list1< + ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int &> > > + > + > + > + p3_type; + p3_type p3 = proto::unpack_expr<proto::tag::unary_plus, mydomain>(fusion::make_tuple(boost::ref(i))); + BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42); + + typedef + ewrap< + proto::basic_expr< + proto::tag::plus + , proto::list2< + p3_type & + , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > > + > + > + > + p4_type; + p4_type p4 = proto::unpack_expr<proto::tag::plus>(fusion::make_tuple(boost::ref(p3), 0)); + BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42); +} + +void test_unpack_expr_functional() +{ + int i = 42; + proto::terminal<int>::type t1 = proto::functional::unpack_expr<proto::tag::terminal>()(fusion::make_tuple(1)); + proto::terminal<int &>::type t2 = proto::functional::unpack_expr<proto::tag::terminal>()(fusion::make_tuple(boost::ref(i))); + proto::unary_plus<proto::terminal<int>::type>::type p1 = proto::functional::unpack_expr<proto::tag::unary_plus>()(fusion::make_tuple(1)); + proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::functional::unpack_expr<proto::tag::unary_plus>()(fusion::make_tuple(boost::ref(i))); + BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42); + + typedef + ewrap< + proto::basic_expr< + proto::tag::unary_plus + , proto::list1< + ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int &> > > + > + > + > + p3_type; + p3_type p3 = proto::functional::unpack_expr<proto::tag::unary_plus, mydomain>()(fusion::make_tuple(boost::ref(i))); + BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42); + + typedef + ewrap< + proto::basic_expr< + proto::tag::plus + , proto::list2< + p3_type & + , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > > + > + > + > + p4_type; + p4_type p4 = proto::functional::unpack_expr<proto::tag::plus>()(fusion::make_tuple(boost::ref(p3), 0)); + BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42); +} + +#if BOOST_WORKAROUND(BOOST_MSVC, == 1310) +#define _byref(x) call<proto::_byref(x)> +#define _byval(x) call<proto::_byval(x)> +#define Minus(x) proto::call<Minus(x)> +#endif + +// Turn all terminals held by reference into ones held by value +struct ByVal + : proto::or_< + proto::when<proto::terminal<proto::_>, proto::_make_terminal(proto::_byval(proto::_value))> + , proto::when<proto::nary_expr<proto::_, proto::vararg<ByVal> > > + > +{}; + +// Turn all terminals held by value into ones held by reference (not safe in general) +struct ByRef + : proto::or_< + proto::when<proto::terminal<proto::_>, proto::_make_terminal(proto::_byref(proto::_value))> + , proto::when<proto::nary_expr<proto::_, proto::vararg<ByRef> > > + > +{}; + +// turn all proto::plus nodes to minus nodes: +struct Minus + : proto::or_< + proto::when<proto::terminal<proto::_> > + , proto::when<proto::plus<Minus, Minus>, proto::_make_minus(Minus(proto::_left), Minus(proto::_right)) > + > +{}; + +struct Square + : proto::or_< + // Not creating new proto::terminal nodes here, + // so hold the existing terminals by reference: + proto::when<proto::terminal<proto::_>, proto::_make_multiplies(proto::_, proto::_)> + , proto::when<proto::plus<Square, Square> > + > +{}; + +#if BOOST_WORKAROUND(BOOST_MSVC, == 1310) +#undef _byref +#undef _byval +#undef Minus +#endif + +void test_make_expr_transform() +{ + proto::plus< + proto::terminal<int>::type + , proto::terminal<int>::type + >::type t1 = ByVal()(proto::as_expr(1) + 1); + + proto::plus< + proto::terminal<int const &>::type + , proto::terminal<int const &>::type + >::type t2 = ByRef()(proto::as_expr(1) + 1); + + proto::minus< + proto::terminal<int>::type const & + , proto::terminal<int const &>::type const & + >::type t3 = Minus()(proto::as_expr(1) + 1); + + proto::plus< + proto::multiplies<proto::terminal<int>::type const &, proto::terminal<int>::type const &>::type + , proto::multiplies<proto::terminal<int const &>::type const &, proto::terminal<int const &>::type const &>::type + >::type t4 = Square()(proto::as_expr(1) + 1); +} + + +struct length_impl {}; +struct dot_impl {}; + +proto::terminal<length_impl>::type const length = {{}}; +proto::terminal<dot_impl>::type const dot = {{}}; + +// work around msvc bugs... +#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500)) +#define _byref(a) call<proto::_byref(a)> +#define _byval(a) call<proto::_byval(a)> +#define _child1(a) call<proto::_child1(a)> +#define _make_terminal(a) call<proto::_make_terminal(a)> +#define _make_function(a,b,c) call<proto::_make_function(a,b,c)> +#define dot_impl() proto::make<dot_impl()> +#endif + +// convert length(a) < length(b) to dot(a,a) < dot(b,b) +struct Convert + : proto::when< + proto::less< + proto::function<proto::terminal<length_impl>, proto::_> + , proto::function<proto::terminal<length_impl>, proto::_> + > + , proto::_make_less( + proto::_make_function( + proto::_make_terminal(dot_impl()) + , proto::_child1(proto::_child0) + , proto::_child1(proto::_child0) + ) + , proto::_make_function( + proto::_make_terminal(dot_impl()) + , proto::_child1(proto::_child1) + , proto::_child1(proto::_child1) + ) + ) + > +{}; + +template<typename Expr> +void test_make_expr_transform2_test(Expr const &expr) +{ + void const *addr1 = boost::addressof(proto::child_c<1>(proto::child_c<0>(expr))); + void const *addr2 = boost::addressof(proto::child_c<1>(proto::child_c<0>(Convert()(expr)))); + BOOST_CHECK_EQUAL(addr1, addr2); + + BOOST_CHECK_EQUAL(1, proto::value(proto::child_c<1>(proto::child_c<0>(expr)))); + BOOST_CHECK_EQUAL(1, proto::value(proto::child_c<1>(proto::child_c<0>(Convert()(expr))))); +} + +void test_make_expr_transform2() +{ + test_make_expr_transform2_test(length(1) < length(2)); +} + +#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500)) +#undef _byref +#undef _byval +#undef _child1 +#undef _make_terminal +#undef _make_function +#undef dot_impl +#endif + +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 proto::make_expr, proto::unpack_expr and friends"); + + test->add(BOOST_TEST_CASE(&test_make_expr)); + test->add(BOOST_TEST_CASE(&test_make_expr_ref)); + test->add(BOOST_TEST_CASE(&test_make_expr_functional)); + test->add(BOOST_TEST_CASE(&test_make_expr_functional_ref)); + test->add(BOOST_TEST_CASE(&test_unpack_expr)); + test->add(BOOST_TEST_CASE(&test_unpack_expr_functional)); + test->add(BOOST_TEST_CASE(&test_make_expr_transform)); + test->add(BOOST_TEST_CASE(&test_make_expr_transform2)); + + return test; +} diff --git a/src/boost/libs/proto/test/matches.cpp b/src/boost/libs/proto/test/matches.cpp new file mode 100644 index 00000000..60b8f725 --- /dev/null +++ b/src/boost/libs/proto/test/matches.cpp @@ -0,0 +1,319 @@ +/////////////////////////////////////////////////////////////////////////////// +// matches.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 <string> +#include <iostream> +#include <boost/config.hpp> +#include <boost/detail/workaround.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/mpl/placeholders.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/proto/core.hpp> +#include <boost/proto/debug.hpp> +#include <boost/proto/transform/arg.hpp> +#include <boost/test/unit_test.hpp> + +namespace mpl = boost::mpl; +namespace proto = boost::proto; +namespace fusion = boost::fusion; + +struct int_convertible +{ + int_convertible() {} + operator int() const { return 0; } +}; + +struct Input + : proto::or_< + proto::shift_right< proto::terminal< std::istream & >, proto::_ > + , proto::shift_right< Input, proto::_ > + > +{}; + +struct Output + : proto::or_< + proto::shift_left< proto::terminal< std::ostream & >, proto::_ > + , proto::shift_left< Output, proto::_ > + > +{}; + +proto::terminal< std::istream & >::type const cin_ = {std::cin}; +proto::terminal< std::ostream & >::type const cout_ = {std::cout}; + +struct Anything + : proto::or_< + proto::terminal<proto::_> + , proto::nary_expr<proto::_, proto::vararg<Anything> > + > +{}; + +void a_function() {} + +struct MyCases +{ + template<typename Tag> + struct case_ + : proto::not_<proto::_> + {}; +}; + +template<> +struct MyCases::case_<proto::tag::shift_right> + : proto::_ +{}; + +template<> +struct MyCases::case_<proto::tag::plus> + : proto::_ +{}; + +enum binary_representation_enum +{ + magnitude + , two_complement +}; + +typedef + mpl::integral_c<binary_representation_enum, magnitude> +magnitude_c; + +typedef + mpl::integral_c<binary_representation_enum, two_complement> +two_complement_c; + +template<typename Type, typename Representation> +struct number +{}; + +struct NumberGrammar + : proto::or_ < + proto::terminal<number<proto::_, two_complement_c> > + , proto::terminal<number<proto::_, magnitude_c> > + > +{}; + +struct my_terminal +{}; + +template<typename T> +struct a_template +{}; + +template<typename Expr> +struct my_expr; + +struct my_domain + : proto::domain<proto::pod_generator<my_expr> > +{}; + +template<typename Expr> +struct my_expr +{ + BOOST_PROTO_BASIC_EXTENDS(Expr, my_expr, my_domain) +}; + +void test_matches() +{ + proto::assert_matches< proto::_ >( proto::lit(1) ); + proto::assert_matches< proto::_ >( proto::as_child(1) ); + proto::assert_matches< proto::_ >( proto::as_expr(1) ); + + proto::assert_matches< proto::terminal<int> >( proto::lit(1) ); + proto::assert_matches< proto::terminal<int> >( proto::as_child(1) ); + proto::assert_matches< proto::terminal<int> >( proto::as_expr(1) ); + + proto::assert_matches_not< proto::terminal<int> >( proto::lit('a') ); + proto::assert_matches_not< proto::terminal<int> >( proto::as_child('a') ); + proto::assert_matches_not< proto::terminal<int> >( proto::as_expr('a') ); + + proto::assert_matches< proto::terminal<proto::convertible_to<int> > >( proto::lit('a') ); + proto::assert_matches< proto::terminal<proto::convertible_to<int> > >( proto::as_child('a') ); + proto::assert_matches< proto::terminal<proto::convertible_to<int> > >( proto::as_expr('a') ); + + proto::assert_matches_not< proto::terminal<int> >( proto::lit((int_convertible())) ); + proto::assert_matches_not< proto::terminal<int> >( proto::as_child((int_convertible())) ); + proto::assert_matches_not< proto::terminal<int> >( proto::as_expr((int_convertible())) ); + + proto::assert_matches< proto::terminal<proto::convertible_to<int> > >( proto::lit((int_convertible())) ); + proto::assert_matches< proto::terminal<proto::convertible_to<int> > >( proto::as_child((int_convertible())) ); + proto::assert_matches< proto::terminal<proto::convertible_to<int> > >( proto::as_expr((int_convertible())) ); + + proto::assert_matches< proto::if_<boost::is_same<proto::_value, int>() > >( proto::lit(1) ); + proto::assert_matches_not< proto::if_<boost::is_same<proto::_value, int>() > >( proto::lit('a') ); + + proto::assert_matches< + proto::and_< + proto::terminal<proto::_> + , proto::if_<boost::is_same<proto::_value, int>() > + > + >( proto::lit(1) ); + + proto::assert_matches_not< + proto::and_< + proto::terminal<proto::_> + , proto::if_<boost::is_same<proto::_value, int>() > + > + >( proto::lit('a') ); + + proto::assert_matches< proto::terminal<char const *> >( proto::lit("hello") ); + proto::assert_matches< proto::terminal<char const *> >( proto::as_child("hello") ); + proto::assert_matches< proto::terminal<char const *> >( proto::as_expr("hello") ); + + proto::assert_matches< proto::terminal<char const[6]> >( proto::lit("hello") ); + proto::assert_matches< proto::terminal<char const (&)[6]> >( proto::as_child("hello") ); + proto::assert_matches< proto::terminal<char const[6]> >( proto::as_expr("hello") ); + + proto::assert_matches< proto::terminal<char [6]> >( proto::lit("hello") ); + proto::assert_matches< proto::terminal<char [6]> >( proto::as_child("hello") ); + proto::assert_matches< proto::terminal<char [6]> >( proto::as_expr("hello") ); + + proto::assert_matches< proto::terminal<char const[proto::N]> >( proto::lit("hello") ); + proto::assert_matches< proto::terminal<char const (&)[proto::N]> >( proto::as_child("hello") ); + proto::assert_matches< proto::terminal<char const[proto::N]> >( proto::as_expr("hello") ); + + proto::assert_matches< proto::terminal<char [proto::N]> >( proto::lit("hello") ); + proto::assert_matches< proto::terminal<char [proto::N]> >( proto::as_child("hello") ); + proto::assert_matches< proto::terminal<char [proto::N]> >( proto::as_expr("hello") ); + + proto::assert_matches< proto::terminal<wchar_t const[proto::N]> >( proto::lit(L"hello") ); + proto::assert_matches< proto::terminal<wchar_t const (&)[proto::N]> >( proto::as_child(L"hello") ); + proto::assert_matches< proto::terminal<wchar_t const[proto::N]> >( proto::as_expr(L"hello") ); + + proto::assert_matches< proto::terminal<wchar_t [proto::N]> >( proto::lit(L"hello") ); + proto::assert_matches< proto::terminal<wchar_t [proto::N]> >( proto::as_child(L"hello") ); + proto::assert_matches< proto::terminal<wchar_t [proto::N]> >( proto::as_expr(L"hello") ); + + proto::assert_matches_not< proto::if_<boost::is_same<proto::_value, int>()> >( proto::lit("hello") ); + + proto::assert_matches< proto::terminal<std::string> >( proto::lit(std::string("hello")) ); + proto::assert_matches< proto::terminal<std::string> >( proto::as_child(std::string("hello")) ); + proto::assert_matches< proto::terminal<std::string> >( proto::as_expr(std::string("hello")) ); + + proto::assert_matches< proto::terminal<std::basic_string<proto::_> > >( proto::lit(std::string("hello")) ); + proto::assert_matches< proto::terminal<std::basic_string<proto::_> > >( proto::as_child(std::string("hello")) ); + proto::assert_matches< proto::terminal<std::basic_string<proto::_> > >( proto::as_expr(std::string("hello")) ); + + proto::assert_matches_not< proto::terminal<std::basic_string<proto::_> > >( proto::lit(1) ); + proto::assert_matches_not< proto::terminal<std::basic_string<proto::_> > >( proto::as_child(1) ); + proto::assert_matches_not< proto::terminal<std::basic_string<proto::_> > >( proto::as_expr(1) ); + + proto::assert_matches_not< proto::terminal<std::basic_string<proto::_,proto::_,proto::_> > >( proto::lit(1) ); + proto::assert_matches_not< proto::terminal<std::basic_string<proto::_,proto::_,proto::_> > >( proto::as_child(1) ); + proto::assert_matches_not< proto::terminal<std::basic_string<proto::_,proto::_,proto::_> > >( proto::as_expr(1) ); + + #if BOOST_WORKAROUND(__HP_aCC, BOOST_TESTED_AT(61700)) + typedef std::string const const_string; + #else + typedef std::string const_string; + #endif + + proto::assert_matches< proto::terminal<std::basic_string<proto::_> const & > >( proto::lit(const_string("hello")) ); + proto::assert_matches< proto::terminal<std::basic_string<proto::_> const & > >( proto::as_child(const_string("hello")) ); + proto::assert_matches_not< proto::terminal<std::basic_string<proto::_> const & > >( proto::as_expr(const_string("hello")) ); + + proto::assert_matches< proto::terminal< void(&)() > >( proto::lit(a_function) ); + proto::assert_matches< proto::terminal< void(&)() > >( proto::as_child(a_function) ); + proto::assert_matches< proto::terminal< void(&)() > >( proto::as_expr(a_function) ); + + proto::assert_matches_not< proto::terminal< void(*)() > >( proto::lit(a_function) ); + proto::assert_matches_not< proto::terminal< void(*)() > >( proto::as_child(a_function) ); + proto::assert_matches_not< proto::terminal< void(*)() > >( proto::as_expr(a_function) ); + + proto::assert_matches< proto::terminal< proto::convertible_to<void(*)()> > >( proto::lit(a_function) ); + proto::assert_matches< proto::terminal< proto::convertible_to<void(*)()> > >( proto::as_child(a_function) ); + proto::assert_matches< proto::terminal< proto::convertible_to<void(*)()> > >( proto::as_expr(a_function) ); + + proto::assert_matches< proto::terminal< void(*)() > >( proto::lit(&a_function) ); + proto::assert_matches< proto::terminal< void(*)() > >( proto::as_child(&a_function) ); + proto::assert_matches< proto::terminal< void(*)() > >( proto::as_expr(&a_function) ); + + proto::assert_matches< proto::terminal< void(* const &)() > >( proto::lit(&a_function) ); + proto::assert_matches< proto::terminal< void(* const &)() > >( proto::as_child(&a_function) ); + proto::assert_matches_not< proto::terminal< void(* const &)() > >( proto::as_expr(&a_function) ); + + proto::assert_matches< + proto::or_< + proto::if_<boost::is_same<proto::_value, char>() > + , proto::if_<boost::is_same<proto::_value, int>() > + > + >( proto::lit(1) ); + + proto::assert_matches_not< + proto::or_< + proto::if_<boost::is_same<proto::_value, char>() > + , proto::if_<boost::is_same<proto::_value, int>() > + > + >( proto::lit(1u) ); + + proto::assert_matches< Input >( cin_ >> 1 >> 2 >> 3 ); + proto::assert_matches_not< Output >( cin_ >> 1 >> 2 >> 3 ); + + proto::assert_matches< Output >( cout_ << 1 << 2 << 3 ); + proto::assert_matches_not< Input >( cout_ << 1 << 2 << 3 ); + + proto::assert_matches< proto::function< proto::terminal<int>, proto::vararg< proto::terminal<char> > > >( proto::lit(1)('a','b','c','d') ); + proto::assert_matches_not< proto::function< proto::terminal<int>, proto::vararg< proto::terminal<char> > > >( proto::lit(1)('a','b','c',"d") ); + + proto::assert_matches< Anything >( cout_ << 1 << +proto::lit('a') << proto::lit(1)('a','b','c',"d") ); + + proto::assert_matches< proto::switch_<MyCases> >( proto::lit(1) >> 'a' ); + proto::assert_matches< proto::switch_<MyCases> >( proto::lit(1) + 'a' ); + proto::assert_matches_not< proto::switch_<MyCases> >( proto::lit(1) << 'a' ); + + number<int, two_complement_c> num; + proto::assert_matches<NumberGrammar>(proto::as_expr(num)); + + // check custom terminal types + { + proto::nullary_expr<my_terminal, int>::type i = {0}; + + proto::assert_matches<proto::nullary_expr<my_terminal, proto::_> >( i ); + proto::assert_matches_not<proto::terminal<proto::_> >( i ); + + proto::terminal<int>::type j = {0}; + proto::assert_matches<proto::terminal<proto::_> >( j ); + proto::assert_matches_not<proto::nullary_expr<my_terminal, proto::_> >( j ); + + proto::assert_matches<proto::nullary_expr<proto::_, proto::_> >( i ); + } + + // check 0 and 1 arg forms or or_ and and_ + { + proto::assert_matches< proto::and_<> >( proto::lit(1) ); + proto::assert_matches_not< proto::or_<> >( proto::lit(1) ); + + proto::assert_matches< proto::and_<proto::terminal<int> > >( proto::lit(1) ); + proto::assert_matches< proto::or_<proto::terminal<int> > >( proto::lit(1) ); + } + + // Test lambda matches with arrays, a corner case that had + // a bug that was reported by Antoine de Maricourt on boost@lists.boost.org + { + a_template<int[3]> a; + proto::assert_matches< proto::terminal< a_template<proto::_> > >( proto::lit(a) ); + } + + // Test that the actual derived expression type makes it through to proto::if_ + { + my_expr<proto::terminal<int>::type> e = {{1}}; + proto::assert_matches< proto::if_<boost::is_same<proto::domain_of<proto::_>, my_domain>()> >( e ); + } +} + +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 proto::matches<>"); + + test->add(BOOST_TEST_CASE(&test_matches)); + + return test; +} + diff --git a/src/boost/libs/proto/test/mem_ptr.cpp b/src/boost/libs/proto/test/mem_ptr.cpp new file mode 100644 index 00000000..5326c665 --- /dev/null +++ b/src/boost/libs/proto/test/mem_ptr.cpp @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// mem_ptr.hpp +// +// Copyright 2009 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 <boost/mpl/print.hpp> +#include <iostream> +#include <boost/shared_ptr.hpp> +#include <boost/proto/proto.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/utility/result_of.hpp> +#include <boost/test/unit_test.hpp> + +namespace proto = boost::proto; +using proto::_; + +struct evaluator + : proto::when<_, proto::_default<evaluator> > +{}; + +template<typename Ret, typename Expr> +void assert_result_type(Expr &) +{ + // check that the return type as calculated by the _default transform + // is correct. + BOOST_MPL_ASSERT(( + boost::is_same< + Ret + , typename boost::result_of<evaluator(Expr &)>::type + > + )); + + // check that the return type as calculated by the default_context + // is correct. + BOOST_MPL_ASSERT(( + boost::is_same< + Ret + , typename boost::result_of<proto::functional::eval(Expr &, proto::default_context &)>::type + > + )); +} + +/////////////////////////////////////////////////////////////////////////////// +struct S +{ + S() : x(-42) {} + int x; +}; + +// like a normal terminal except with an operator() that can +// accept non-const lvalues (Proto's only accepts const lvalues) +template<typename T, typename Dummy = proto::is_proto_expr> +struct my_terminal +{ + typedef typename proto::terminal<T>::type my_terminal_base; + BOOST_PROTO_BASIC_EXTENDS(my_terminal_base, my_terminal, proto::default_domain) + + template<typename A0> + typename proto::result_of::make_expr<proto::tag::function, my_terminal const &, A0 &>::type const + operator()(A0 &a0) const + { + return proto::make_expr<proto::tag::function>(boost::ref(*this), boost::ref(a0)); + } + + template<typename A0> + typename proto::result_of::make_expr<proto::tag::function, my_terminal const &, A0 const &>::type const + operator()(A0 const &a0) const + { + return proto::make_expr<proto::tag::function>(boost::ref(*this), boost::ref(a0)); + } +}; + +my_terminal<int S::*> test1 = {{ &S::x }}; + +// Some tests with the default transform +void test_refs_transform() +{ + S s; + BOOST_REQUIRE_EQUAL(s.x, -42); + + // Check that evaluating a memptr invocation with a + // non-const lvalue argument yields the member as a + // non-const lvalue + assert_result_type<int &>(test1(s)); + evaluator()(test1(s)) = 0; + BOOST_CHECK_EQUAL(s.x, 0); + + // Ditto for reference_wrappers + assert_result_type<int &>(test1(boost::ref(s))); + evaluator()(test1(boost::ref(s))) = 42; + BOOST_CHECK_EQUAL(s.x, 42); + + // Check that evaluating a memptr invocation with a + // const lvalue argument yields the member as a + // const lvalue + S const &rcs = s; + assert_result_type<int const &>(test1(rcs)); + int const &s_x = evaluator()(test1(rcs)); + BOOST_CHECK_EQUAL(&s.x, &s_x); +} + +// Some tests with the default context +void test_refs_context() +{ + proto::default_context ctx; + S s; + BOOST_REQUIRE_EQUAL(s.x, -42); + + // Check that evaluating a memptr invocation with a + // non-const lvalue argument yields the member as a + // non-const lvalue + assert_result_type<int &>(test1(s)); + proto::eval(test1(s), ctx) = 0; + BOOST_CHECK_EQUAL(s.x, 0); + + // Ditto for reference_wrappers + assert_result_type<int &>(test1(boost::ref(s))); + proto::eval(test1(boost::ref(s)), ctx) = 42; + BOOST_CHECK_EQUAL(s.x, 42); + + // Check that evaluating a memptr invocation with a + // const lvalue argument yields the member as a + // const lvalue + S const &rcs = s; + assert_result_type<int const &>(test1(rcs)); + int const &s_x = proto::eval(test1(rcs), ctx); + BOOST_CHECK_EQUAL(&s.x, &s_x); +} + +void test_ptrs_transform() +{ + S s; + BOOST_REQUIRE_EQUAL(s.x, -42); + + // Check that evaluating a memptr invocation with a + // pointer to a non-const argument yields the member as a + // non-const lvalue + assert_result_type<int &>(test1(&s)); + evaluator()(test1(&s)) = 0; + BOOST_CHECK_EQUAL(s.x, 0); + + S* ps = &s; + assert_result_type<int &>(test1(ps)); + evaluator()(test1(ps)) = 42; + BOOST_CHECK_EQUAL(s.x, 42); + + boost::shared_ptr<S> const sp(new S); + BOOST_REQUIRE_EQUAL(sp->x, -42); + + // Ditto for shared_ptr (which hook the get_pointer() + // customization point) + assert_result_type<int &>(test1(sp)); + evaluator()(test1(sp)) = 0; + BOOST_CHECK_EQUAL(sp->x, 0); + + // Check that evaluating a memptr invocation with a + // const lvalue argument yields the member as a + // const lvalue + S const &rcs = s; + assert_result_type<int const &>(test1(&rcs)); + int const &s_x0 = evaluator()(test1(&rcs)); + BOOST_CHECK_EQUAL(&s.x, &s_x0); + + S const *pcs = &s; + assert_result_type<int const &>(test1(pcs)); + int const &s_x1 = evaluator()(test1(pcs)); + BOOST_CHECK_EQUAL(&s.x, &s_x1); + + boost::shared_ptr<S const> spc(new S); + BOOST_REQUIRE_EQUAL(spc->x, -42); + + assert_result_type<int const &>(test1(spc)); + int const &s_x2 = evaluator()(test1(spc)); + BOOST_CHECK_EQUAL(&spc->x, &s_x2); +} + +void test_ptrs_context() +{ + proto::default_context ctx; + S s; + BOOST_REQUIRE_EQUAL(s.x, -42); + + // Check that evaluating a memptr invocation with a + // pointer to a non-const argument yields the member as a + // non-const lvalue + assert_result_type<int &>(test1(&s)); + proto::eval(test1(&s), ctx) = 0; + BOOST_CHECK_EQUAL(s.x, 0); + + S* ps = &s; + assert_result_type<int &>(test1(ps)); + proto::eval(test1(ps), ctx) = 42; + BOOST_CHECK_EQUAL(s.x, 42); + + boost::shared_ptr<S> const sp(new S); + BOOST_REQUIRE_EQUAL(sp->x, -42); + + // Ditto for shared_ptr (which hook the get_pointer() + // customization point) + assert_result_type<int &>(test1(sp)); + proto::eval(test1(sp), ctx) = 0; + BOOST_CHECK_EQUAL(sp->x, 0); + + // Check that evaluating a memptr invocation with a + // const lvalue argument yields the member as a + // const lvalue + S const &rcs = s; + assert_result_type<int const &>(test1(&rcs)); + int const &s_x0 = proto::eval(test1(&rcs), ctx); + BOOST_CHECK_EQUAL(&s.x, &s_x0); + + S const *pcs = &s; + assert_result_type<int const &>(test1(pcs)); + int const &s_x1 = proto::eval(test1(pcs), ctx); + BOOST_CHECK_EQUAL(&s.x, &s_x1); + + boost::shared_ptr<S const> spc(new S); + BOOST_REQUIRE_EQUAL(spc->x, -42); + + assert_result_type<int const &>(test1(spc)); + int const &s_x2 = proto::eval(test1(spc), ctx); + BOOST_CHECK_EQUAL(&spc->x, &s_x2); +} + +/////////////////////////////////////////////////////////////////////////////// +struct T +{ + int x; +}; + +proto::terminal<int T::*>::type test2 = { &T::x }; + +int const *get_pointer(T const &t) +{ + return &t.x; +} + +void with_get_pointer_transform() +{ + T t; + evaluator()(test2(t)); +} + +/////////////////////////////////////////////////////////////////////////////// +template<typename T> +struct dumb_ptr +{ + dumb_ptr(T *p_) : p(p_) {} + + friend T const *get_pointer(dumb_ptr const &p) + { + return p.p; + } + + T *p; +}; + +struct U : dumb_ptr<U> +{ + U() : dumb_ptr<U>(this), x(42) {} + int x; +}; + +my_terminal<U *dumb_ptr<U>::*> U_p = {{&U::p}}; +my_terminal<int U::*> U_x = {{&U::x}}; + +void potentially_ambiguous_transform() +{ + U u; + + // This should yield a non-const reference to a pointer-to-const + U *&up = evaluator()(U_p(u)); + BOOST_CHECK_EQUAL(&up, &u.p); + + // This should yield a non-const reference to a pointer-to-const + int &ux = evaluator()(U_x(u)); + BOOST_CHECK_EQUAL(&ux, &u.x); +} + + +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 handling of member pointers by the default transform and default contexts"); + + test->add(BOOST_TEST_CASE(&test_refs_transform)); + test->add(BOOST_TEST_CASE(&test_refs_context)); + + test->add(BOOST_TEST_CASE(&test_ptrs_transform)); + test->add(BOOST_TEST_CASE(&test_ptrs_context)); + + test->add(BOOST_TEST_CASE(&with_get_pointer_transform)); + + test->add(BOOST_TEST_CASE(&potentially_ambiguous_transform)); + + return test; +} diff --git a/src/boost/libs/proto/test/mpl.cpp b/src/boost/libs/proto/test/mpl.cpp new file mode 100644 index 00000000..292e582b --- /dev/null +++ b/src/boost/libs/proto/test/mpl.cpp @@ -0,0 +1,67 @@ +/////////////////////////////////////////////////////////////////////////////// +// mpl.hpp +// +// Copyright 2012 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 <boost/proto/proto.hpp> +#include <boost/fusion/mpl.hpp> +#include <boost/mpl/pop_back.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/static_assert.hpp> +#include <boost/test/unit_test.hpp> +namespace mpl = boost::mpl; +namespace proto = boost::proto; +namespace fusion = boost::fusion; +using proto::_; + +template<class E> +struct my_expr; + +struct my_domain + : proto::domain<proto::generator<my_expr> > +{}; + +template<class E> +struct my_expr + : proto::extends<E, my_expr<E>, my_domain> +{ + my_expr(E const &e = E()) + : proto::extends<E, my_expr<E>, my_domain>(e) + {} + + typedef fusion::fusion_sequence_tag tag; +}; + +template<typename T> +void test_impl(T const &) +{ + typedef typename mpl::pop_back<T>::type result_type; + BOOST_STATIC_ASSERT( + (boost::is_same< + result_type + , my_expr<proto::basic_expr<proto::tag::plus, proto::list1<my_expr<proto::terminal<int>::type>&> > > + >::value) + ); +} + +// Test that we can call mpl algorithms on proto expression types, and get proto expression types back +void test_mpl() +{ + my_expr<proto::terminal<int>::type> i; + test_impl(i + i); +} + +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 proto mpl integration via fusion"); + + test->add(BOOST_TEST_CASE(&test_mpl)); + + return test; +} diff --git a/src/boost/libs/proto/test/noinvoke.cpp b/src/boost/libs/proto/test/noinvoke.cpp new file mode 100644 index 00000000..05e738a1 --- /dev/null +++ b/src/boost/libs/proto/test/noinvoke.cpp @@ -0,0 +1,116 @@ +/////////////////////////////////////////////////////////////////////////////// +// noinvoke.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 <boost/proto/core.hpp> +#include <boost/proto/transform/make.hpp> +#include <boost/type_traits/add_pointer.hpp> +#include <boost/type_traits/remove_pointer.hpp> +#include <boost/test/unit_test.hpp> +namespace proto=boost::proto; +using proto::_; + +struct Test + : proto::when< + _ + , proto::noinvoke< + // This remove_pointer invocation is bloked by noinvoke + boost::remove_pointer< + // This add_pointer invocation is *not* blocked by noinvoke + boost::add_pointer<_> + > + >() + > +{}; + +struct Test2 + : proto::when< + _ + // This add_pointer gets invoked because a substitution takes place + // within it. + , boost::add_pointer< + proto::noinvoke< + // This remove_pointer invocation is bloked by noinvoke + boost::remove_pointer< + // This add_pointer invocation is *not* blocked by noinvoke + boost::add_pointer<_> + > + > + >() + > +{}; + +template<typename T, typename U> +struct select2nd +{ + typedef U type; +}; + +struct Test3 + : proto::when< + _ + // This add_pointer gets invoked because a substitution takes place + // within it. + , select2nd< + void + , proto::noinvoke< + // This remove_pointer invocation is bloked by noinvoke + select2nd< + void + // This add_pointer invocation is *not* blocked by noinvoke + , boost::add_pointer<_> + > + > + >() + > +{}; + + +void test_noinvoke() +{ + typedef proto::terminal<int>::type Int; + Int i = {42}; + + BOOST_MPL_ASSERT(( + boost::is_same< + boost::result_of<Test(Int)>::type + , boost::remove_pointer<Int *> + > + )); + + boost::remove_pointer<Int *> t = Test()(i); + + BOOST_MPL_ASSERT(( + boost::is_same< + boost::result_of<Test2(Int)>::type + , boost::remove_pointer<Int *> * + > + )); + + boost::remove_pointer<Int *> * t2 = Test2()(i); + + BOOST_MPL_ASSERT(( + boost::is_same< + boost::result_of<Test3(Int)>::type + , select2nd<void, Int *> + > + )); + + select2nd<void, Int *> t3 = Test3()(i); +} + +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 proto::noinvoke"); + + test->add(BOOST_TEST_CASE(&test_noinvoke)); + + return test; +} diff --git a/src/boost/libs/proto/test/pack_expansion.cpp b/src/boost/libs/proto/test/pack_expansion.cpp new file mode 100644 index 00000000..7aacb32f --- /dev/null +++ b/src/boost/libs/proto/test/pack_expansion.cpp @@ -0,0 +1,124 @@ +/////////////////////////////////////////////////////////////////////////////// +// pack_expansion.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 <boost/proto/proto.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/typeof/typeof.hpp> + +namespace mpl = boost::mpl; +namespace proto = boost::proto; +using proto::_; + +template<typename T> T declval(); + +struct eval_ : proto::callable +{ + template<typename Sig> + struct result; + +#define UNARY_OP(TAG, OP) \ + template<typename This, typename Arg> \ + struct result<This(proto::tag::TAG, Arg)> \ + { \ + BOOST_TYPEOF_NESTED_TYPEDEF_TPL(nested, (OP declval<Arg>())) \ + typedef typename nested::type type; \ + }; \ + \ + template<typename Arg> \ + typename result<eval_(proto::tag::TAG, Arg)>::type \ + operator()(proto::tag::TAG, Arg arg) const \ + { \ + return OP arg; \ + } \ + /**/ + +#define BINARY_OP(TAG, OP) \ + template<typename This, typename Left, typename Right> \ + struct result<This(proto::tag::TAG, Left, Right)> \ + { \ + BOOST_TYPEOF_NESTED_TYPEDEF_TPL(nested, (declval<Left>() OP declval<Right>())) \ + typedef typename nested::type type; \ + }; \ + \ + template<typename Left, typename Right> \ + typename result<eval_(proto::tag::TAG, Left, Right)>::type \ + operator()(proto::tag::TAG, Left left, Right right) const \ + { \ + return left OP right; \ + } \ + /**/ + + UNARY_OP(negate, -) + BINARY_OP(plus, +) + BINARY_OP(minus, -) + BINARY_OP(multiplies, *) + BINARY_OP(divides, /) + /*... others ...*/ +}; + +struct eval1 + : proto::or_< + proto::when<proto::terminal<_>, proto::_value> + , proto::otherwise<eval_(proto::tag_of<_>(), eval1(proto::pack(_))...)> + > +{}; + +struct eval2 + : proto::or_< + proto::when<proto::terminal<_>, proto::_value> + , proto::otherwise<proto::call<eval_(proto::tag_of<_>(), eval2(proto::pack(_))...)> > + > +{}; + +void test_call_pack() +{ + proto::terminal<int>::type i = {42}; + int res = eval1()(i); + BOOST_CHECK_EQUAL(res, 42); + res = eval1()(i + 2); + BOOST_CHECK_EQUAL(res, 44); + res = eval1()(i * 2); + BOOST_CHECK_EQUAL(res, 84); + res = eval1()(i * 2 + 4); + BOOST_CHECK_EQUAL(res, 88); + + res = eval2()(i + 2); + BOOST_CHECK_EQUAL(res, 44); + res = eval2()(i * 2); + BOOST_CHECK_EQUAL(res, 84); + res = eval2()(i * 2 + 4); + BOOST_CHECK_EQUAL(res, 88); +} + +struct make_pair + : proto::when< + proto::binary_expr<_, proto::terminal<int>, proto::terminal<int> > + , std::pair<int, int>(proto::_value(proto::pack(_))...) + > +{}; + +void test_make_pack() +{ + proto::terminal<int>::type i = {42}; + std::pair<int, int> p = make_pair()(i + 43); + BOOST_CHECK_EQUAL(p.first, 42); + BOOST_CHECK_EQUAL(p.second, 43); +} + +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 immediate evaluation of proto parse trees"); + + test->add(BOOST_TEST_CASE(&test_call_pack)); + test->add(BOOST_TEST_CASE(&test_make_pack)); + + return test; +} diff --git a/src/boost/libs/proto/test/protect.cpp b/src/boost/libs/proto/test/protect.cpp new file mode 100644 index 00000000..33b05519 --- /dev/null +++ b/src/boost/libs/proto/test/protect.cpp @@ -0,0 +1,106 @@ +/////////////////////////////////////////////////////////////////////////////// +// protect.hpp +// +// Copyright 2012 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 <boost/proto/core.hpp> +#include <boost/proto/transform/make.hpp> +#include <boost/type_traits/add_pointer.hpp> +#include <boost/type_traits/remove_pointer.hpp> +#include <boost/test/unit_test.hpp> +namespace proto=boost::proto; +using proto::_; + +template<typename T> +struct identity +{ + typedef T type; +}; + +struct TestWithMake + : proto::make< proto::protect<_> > +{}; + +struct TestWithMake1 + : proto::make< identity<proto::protect<_> > > +{}; + +struct TestWithMake2 + : proto::make< identity<proto::protect<int> > > +{}; + +struct TestWithMake3 + : proto::make< identity<proto::protect<identity<_> > > > +{}; + +struct TestWithMake4 + : proto::make< identity<proto::protect<identity<int> > > > +{}; + +struct TestWithMake5 + : proto::make< identity<proto::protect<identity<identity<int> > > > > +{}; + +void test_protect_with_make() +{ + proto::terminal<int>::type i = {42}; + + _ t = TestWithMake()(i); + _ t1 = TestWithMake1()(i); + int t2 = TestWithMake2()(i); + identity<_> t3 = TestWithMake3()(i); + identity<int> t4 = TestWithMake4()(i); + identity<identity<int> > t5 = TestWithMake5()(i); +} + +//struct TestWithWhen +// : proto::when<_, proto::protect<_>() > +//{}; + +struct TestWithWhen1 + : proto::when<_, identity<proto::protect<_> >() > +{}; + +struct TestWithWhen2 + : proto::when<_, identity<proto::protect<int> >() > +{}; + +struct TestWithWhen3 + : proto::when<_, identity<proto::protect<identity<_> > >() > +{}; + +struct TestWithWhen4 + : proto::when<_, identity<proto::protect<identity<int> > >() > +{}; + +struct TestWithWhen5 + : proto::when<_, identity<proto::protect<identity<identity<int> > > >() > +{}; + +void test_protect_with_when() +{ + proto::terminal<int>::type i = {42}; + + //_ t = TestWithWhen()(i); + _ t1 = TestWithWhen1()(i); + int t2 = TestWithWhen2()(i); + identity<_> t3 = TestWithWhen3()(i); + identity<int> t4 = TestWithWhen4()(i); + identity<identity<int> > t5 = TestWithWhen5()(i); +} + +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 proto::protect"); + + test->add(BOOST_TEST_CASE(&test_protect_with_make)); + test->add(BOOST_TEST_CASE(&test_protect_with_when)); + + return test; +} diff --git a/src/boost/libs/proto/test/switch.cpp b/src/boost/libs/proto/test/switch.cpp new file mode 100644 index 00000000..be5881f5 --- /dev/null +++ b/src/boost/libs/proto/test/switch.cpp @@ -0,0 +1,95 @@ +/////////////////////////////////////////////////////////////////////////////// +// new_switch.cpp +// +// Copyright 2011 Eric Niebler +// Copyright Pierre Esterie & Joel Falcou. +// 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 <boost/proto/core.hpp> +#include <boost/proto/transform.hpp> +#include <boost/detail/workaround.hpp> +#include <boost/proto/debug.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/mpl/long.hpp> +#include <boost/mpl/bool.hpp> + +namespace proto = boost::proto; + +struct MyCases +{ + template<typename Tag> + struct case_ + : proto::not_<proto::_> + {}; +}; + +template<> +struct MyCases::case_<proto::tag::shift_right> + : proto::_ +{}; + +template<> +struct MyCases::case_<proto::tag::plus> + : proto::_ +{}; + +struct ArityOf; + +struct ArityOfCases +{ + template<typename ArityOf> + struct case_ + : proto::not_<proto::_> + {}; +}; + + +template<> +struct ArityOfCases::case_<boost::mpl::long_<1> > + : boost::proto::when<boost::proto::_, boost::mpl::false_()> +{}; + +template<> +struct ArityOfCases::case_<boost::mpl::long_<2> > + : boost::proto::when<boost::proto::_, boost::mpl::true_()> +{}; + +struct ArityOf + : boost::proto::switch_< + ArityOfCases + , proto::arity_of<proto::_>() + > +{}; + +void test_switch() +{ + // Tests for backward compatibility + proto::assert_matches<proto::switch_<MyCases> >(proto::lit(1) >> 'a'); + proto::assert_matches<proto::switch_<MyCases> >(proto::lit(1) + 'a'); + proto::assert_matches_not<proto::switch_<MyCases> >(proto::lit(1) << 'a'); + + //Test new matching on the Transform result type + ArityOf ar; + + proto::assert_matches_not<ArityOf>(proto::lit(1)); + proto::assert_matches<ArityOf>(proto::lit(1) + 2); + proto::assert_matches<ArityOf>(!proto::lit(1)); + BOOST_CHECK_EQUAL(ar(!proto::lit(1)), false); + BOOST_CHECK_EQUAL(ar(proto::lit(1) + 2), true); +} + +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 proto::switch_<>"); + + test->add(BOOST_TEST_CASE(&test_switch)); + + return test; +} + diff --git a/src/boost/libs/proto/test/toy_spirit.cpp b/src/boost/libs/proto/test/toy_spirit.cpp new file mode 100644 index 00000000..6d2fcad9 --- /dev/null +++ b/src/boost/libs/proto/test/toy_spirit.cpp @@ -0,0 +1,665 @@ +/////////////////////////////////////////////////////////////////////////////// +// toy_spirit.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 <cctype> +#include <string> +#include <cstring> +#include <iostream> +#include <boost/assert.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/proto/core.hpp> +#include <boost/proto/context.hpp> +#include <boost/test/unit_test.hpp> + +namespace boost +{ + // global tags + struct char_tag {}; + struct ichar_tag {}; + struct istring_tag {}; + struct ichar_range_tag {}; + struct never_tag {}; + struct always_tag {}; + struct space_tag {}; + + // global primitives + proto::terminal<char_tag>::type const char_ = {{}}; + proto::terminal<space_tag>::type const space = {{}}; + + using proto::lit; + using proto::literal; +} + +namespace boost { namespace spirit2 +{ + + // handy typedefs + typedef proto::terminal<char_tag>::type anychar_p; + typedef proto::terminal<ichar_tag>::type ianychar_p; + typedef proto::terminal<istring_tag>::type ianystr_p; + typedef proto::terminal<ichar_range_tag>::type ianychar_range_p; + typedef proto::terminal<never_tag>::type never_p; + typedef proto::terminal<space_tag>::type space_p; + + struct SpiritGrammar; + struct SkipperGrammar; + struct SpiritPrimitives; + template<typename Grammar> + struct SpiritComposites; + + struct CharLiteral + : proto::terminal<char> + {}; + + struct NTBSLiteral + : proto::terminal<char const *> + {}; + + struct StdStringLiteral + : proto::terminal<std::string> + {}; + + struct CharParser + : proto::function<anychar_p, CharLiteral> + {}; + + struct ICharParser + : proto::function<ianychar_p, CharLiteral, CharLiteral> + {}; + + struct CharRangeParser + : proto::function<anychar_p, CharLiteral, CharLiteral> + {}; + + struct IStrParser + : proto::function<ianystr_p, StdStringLiteral> + {}; + + struct ICharRangeParser + : proto::function<ianychar_range_p, CharLiteral, CharLiteral> + {}; + + ianychar_p const ichar_ = {{}}; + ianystr_p const istr_ = {{}}; + ianychar_range_p const ichar_range_ = {{}}; + + namespace utility + { + inline bool char_icmp(char ch, char lo, char hi) + { + return ch == lo || ch == hi; + } + + template<typename FwdIter> + inline bool string_cmp(char const *sz, FwdIter &begin, FwdIter end) + { + FwdIter tmp = begin; + for(; *sz; ++tmp, ++sz) + if(tmp == end || *tmp != *sz) + return false; + begin = tmp; + return true; + } + + template<typename FwdIter> + inline bool string_icmp(std::string const &str, FwdIter &begin, FwdIter end) + { + BOOST_ASSERT(0 == str.size() % 2); + FwdIter tmp = begin; + std::string::const_iterator istr = str.begin(), estr = str.end(); + for(; istr != estr; ++tmp, istr += 2) + if(tmp == end || (*tmp != *istr && *tmp != *(istr+1))) + return false; + begin = tmp; + return true; + } + + inline bool in_range(char ch, char lo, char hi) + { + return ch >= lo && ch <= hi; + } + + inline bool in_irange(char ch, char lo, char hi) + { + return in_range(ch, lo, hi) + || in_range(std::tolower(ch), lo, hi) + || in_range(std::toupper(ch), lo, hi); + } + + inline std::string to_istr(char const *sz) + { + std::string res; + res.reserve(std::strlen(sz) * 2); + for(; *sz; ++sz) + { + res.push_back(std::tolower(*sz)); + res.push_back(std::toupper(*sz)); + } + return res; + } + } // namespace utility + + template<typename FwdIter, typename Skipper = never_p> + struct spirit_context + : std::pair<FwdIter, FwdIter> + , proto::callable_context<spirit_context<FwdIter, Skipper> > + { + typedef bool result_type; + typedef FwdIter iterator; + + spirit_context(FwdIter first, FwdIter second, Skipper const &skip = Skipper()) + : std::pair<FwdIter, FwdIter>(first, second) + , skip_(skip) + , in_skip_(false) + {} + + // parse function for anychar_p + bool operator()(proto::tag::terminal, char_tag) + { + this->skip(); + if(this->first == this->second) + return false; + ++this->first; + return true; + } + + // parse function for char_('a') + template<typename Expr> + bool operator()(proto::tag::function, anychar_p, Expr const &expr) + { + this->skip(); + return proto::eval(expr, *this); + } + + // parse function for space_p + bool operator()(proto::tag::terminal, space_tag) + { + this->skip(); + if(this->first == this->second || !std::isspace(*this->first)) + return false; + ++this->first; + return true; + } + + // parse function for bare character literals + bool operator()(proto::tag::terminal, char ch) + { + this->skip(); + if(this->first == this->second || *this->first != ch) + return false; + ++this->first; + return true; + } + + // case-insensitive character parser + template<typename Arg1, typename Arg2> + bool operator()(proto::tag::function, ianychar_p, Arg1 const &arg1, Arg2 const &arg2) + { + this->skip(); + if(this->first == this->second + || !utility::char_icmp(*this->first, proto::value(arg1), proto::value(arg2))) + return false; + ++this->first; + return true; + } + + // parse function for NTBS literals + bool operator()(proto::tag::terminal, char const *sz) + { + this->skip(); + return utility::string_cmp(sz, this->first, this->second); + } + + // parse function for istr_("hello") + template<typename Expr> + bool operator()(proto::tag::function, ianystr_p, Expr const &expr) + { + this->skip(); + return utility::string_icmp(proto::value(expr), this->first, this->second); + } + + // parse function for char_('a','z') + template<typename Arg1, typename Arg2> + bool operator()(proto::tag::function, anychar_p, Arg1 const &arg1, Arg2 const &arg2) + { + BOOST_ASSERT(proto::value(arg1) <= proto::value(arg2)); + this->skip(); + if(this->first == this->second + || !utility::in_range(*this->first, proto::value(arg1), proto::value(arg2))) + return false; + ++this->first; + return true; + } + + // parse function for ichar_range_('a','z') + template<typename Arg1, typename Arg2> + bool operator()(proto::tag::function, ianychar_range_p, Arg1 const &arg1, Arg2 const &arg2) + { + BOOST_ASSERT(proto::value(arg1) <= proto::value(arg2)); + this->skip(); + if(this->first == this->second + || !utility::in_irange(*this->first, proto::value(arg1), proto::value(arg2))) + return false; + ++this->first; + return true; + } + + // parse function for complemented thingies (where thingies are assumed + // to be 1 character wide). + template<typename Expr> + bool operator()(proto::tag::complement, Expr const &expr) + { + this->skip(); + iterator where = this->first; + if(proto::eval(expr, *this)) + return this->first = where, false; + this->first = ++where; + return true; + } + + // never_p parse function always returns false. + bool operator()(proto::tag::terminal, never_tag) + { + return false; + } + + // for A >> B, succeeds if A and B matches. + template<typename Left, typename Right> + bool operator()(proto::tag::shift_right, Left const &left, Right const &right) + { + return proto::eval(left, *this) && proto::eval(right, *this); + } + + // for A | B, succeeds if either A or B matches at this point. + template<typename Left, typename Right> + bool operator()(proto::tag::bitwise_or, Left const &left, Right const &right) + { + iterator where = this->first; + return proto::eval(left, *this) || proto::eval(right, this->reset(where)); + } + + // for *A, greedily match A as many times as possible. + template<typename Expr> + bool operator()(proto::tag::dereference, Expr const &expr) + { + iterator where = this->first; + while(proto::eval(expr, *this)) + where = this->first; + // make sure that when we return true, the iterator is at the correct position! + this->first = where; + return true; + } + + // for +A, greedily match A one or more times. + template<typename Expr> + bool operator()(proto::tag::unary_plus, Expr const &expr) + { + return proto::eval(expr, *this) && proto::eval(*expr, *this); + } + + // for !A, optionally match A. + template<typename Expr> + bool operator()(proto::tag::logical_not, Expr const &expr) + { + iterator where = this->first; + if(!proto::eval(expr, *this)) + this->first = where; + return true; + } + + // for (A - B), matches when A but not B matches. + template<typename Left, typename Right> + bool operator()(proto::tag::minus, Left const &left, Right const &right) + { + iterator where = this->first; + return !proto::eval(right, *this) && proto::eval(left, this->reset(where)); + } + private: + spirit_context &reset(iterator where) + { + this->first = where; + return *this; + } + + void skip() + { + if(!this->in_skip_) + { + this->in_skip_ = true; + while(proto::eval(this->skip_, *this)) + {} + this->in_skip_ = false; + } + } + + Skipper skip_; + bool in_skip_; + }; + + struct as_ichar_parser : proto::callable + { + typedef proto::function< + ianychar_p + , proto::terminal<char>::type + , proto::terminal<char>::type + >::type result_type; + + template<typename Expr> + result_type operator()(Expr const &expr) const + { + char lo = std::tolower(proto::value(proto::child_c<1>(expr))); + char hi = std::toupper(proto::value(proto::child_c<1>(expr))); + result_type that = {ichar_, {lo}, {hi}}; + return that; + } + }; + + struct as_ichar_range_parser : proto::callable + { + typedef proto::function< + ianychar_range_p + , proto::terminal<char>::type + , proto::terminal<char>::type + >::type result_type; + + template<typename Expr> + result_type operator()(Expr const &expr) const + { + char lo = proto::value(proto::child_c<1>(expr)); + char hi = proto::value(proto::child_c<2>(expr)); + result_type that = {ichar_range_, {lo}, {hi}}; + return that; + } + }; + + struct as_ichar_literal : proto::callable + { + typedef proto::function< + ianychar_p + , proto::terminal<char>::type + , proto::terminal<char>::type + >::type result_type; + + template<typename Expr> + result_type operator()(Expr const &expr) const + { + char lo = std::tolower(proto::value(expr)); + char hi = std::toupper(proto::value(expr)); + result_type that = {ichar_, {lo}, {hi}}; + return that; + } + }; + + struct as_intbs_literal : proto::callable + { + typedef proto::function< + ianystr_p + , proto::terminal<std::string>::type + >::type result_type; + + template<typename Expr> + result_type operator()(Expr const &expr) const + { + result_type that = {istr_, {utility::to_istr(proto::value(expr))}}; + return that; + } + }; + + struct as_istdstring_literal : proto::callable + { + typedef proto::function< + ianystr_p + , proto::terminal<std::string>::type + >::type result_type; + + template<typename Expr> + result_type operator()(Expr const &expr) const + { + result_type that = {istr_, {utility::to_istr(proto::value(expr).c_str())}}; + return that; + } + }; + + /////////////////////////////////////////////////////////////////////////// + // Transforms + /////////////////////////////////////////////////////////////////////////// + + struct skip_primitives : proto::transform<skip_primitives> + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef + typename proto::shift_right< + typename proto::dereference<State>::type + , Expr + >::type + result_type; + + result_type operator ()( + typename impl::expr_param expr + , typename impl::state_param state + , typename impl::data_param data + ) const + { + result_type that = {{state}, expr}; + return that; + } + }; + }; + + /////////////////////////////////////////////////////////////////////////// + // Grammar + /////////////////////////////////////////////////////////////////////////// + using proto::_; + + struct SpiritGrammar; + + struct SpiritCaseSensitivePrimitives + : proto::or_< + proto::when<CharParser, as_ichar_parser(_)> + , proto::when<CharLiteral, as_ichar_literal(_)> + , proto::when<NTBSLiteral, as_intbs_literal(_)> + , proto::when<CharRangeParser, as_ichar_range_parser(_)> + , proto::when<StdStringLiteral, as_istdstring_literal(_)> + > + {}; + + struct SpiritCaseInsensitivePrimitives + : proto::or_< + anychar_p + , IStrParser + , ICharParser + , ICharRangeParser + , proto::complement<SpiritPrimitives> + > + {}; + + struct SpiritPrimitives + : proto::or_< + SpiritCaseSensitivePrimitives + , SpiritCaseInsensitivePrimitives + > + {}; + + template<typename Grammar> + struct SpiritComposites + : proto::or_< + proto::bitwise_or< Grammar, Grammar > + , proto::shift_right< Grammar, Grammar > + , proto::minus< Grammar, Grammar > + , proto::dereference< Grammar > + , proto::unary_plus< Grammar > + , proto::logical_not< Grammar > + > + {}; + + // Regular Spirit grammar, has no-case transforms + struct SpiritGrammar + : proto::or_< + SpiritComposites<SpiritGrammar> + , SpiritPrimitives + > + {}; + + // Spirit grammar with the skipper transform + struct SkipperGrammar + : proto::or_< + SpiritComposites<SkipperGrammar> + , proto::when<SpiritPrimitives, skip_primitives> + > + {}; + + /////////////////////////////////////////////////////////////////////////// + // Directives + /////////////////////////////////////////////////////////////////////////// + + struct no_case_directive + { + template<typename Expr> + typename boost::result_of<SpiritGrammar(Expr const &)>::type const + operator [](Expr const &expr) const + { + return SpiritGrammar()(expr); + } + }; + + // no_case + no_case_directive const no_case = {}; + + template<typename Skipper> + struct skip_directive + { + skip_directive(Skipper const &skip) + : skip_(skip) + {} + + template<typename Expr> + typename boost::result_of<SkipperGrammar(Expr const &, Skipper const &)>::type const + operator [](Expr const &expr) const + { + return SkipperGrammar()(expr, this->skip_); + } + private: + Skipper skip_; + }; + + // skip + template<typename Skipper> + skip_directive<Skipper> skip(Skipper const &skip) + { + return skip_directive<Skipper>(skip); + } + + /////////////////////////////////////////////////////////////////////////// + // parse + /////////////////////////////////////////////////////////////////////////// + + template<typename FwdIter, typename Rule> + bool parse(FwdIter begin, FwdIter end, Rule const &rule) + { + // make sure the rule corresponds to the Spirit grammar: + BOOST_MPL_ASSERT((proto::matches<Rule, SpiritGrammar>)); + + spirit_context<FwdIter> ctx(begin, end); + return proto::eval(rule, ctx); + } + + // parse with a skip parser can be implemented in one of two ways: + // Method 1) + // The skip parser is passed to all the parsers which invoke it + // before they invoke themselves. This is how Spirit-1 does it, + // and it is the cause of the Scanner Business. However, it has + // the advantage of not needing a parser transformation phase. + // Method 2) + // Transform the expression template to insert the skip parser + // in between all sequenced parsers. That is, transform (A >> B) + // to (*skip >> A >> *skip >> B). This has the advantage of making + // it unnecessary to pass the scanner to all the parsers, which + // means its type doesn't show up in function signatures, avoiding + // the Scanner Business. + // Recommendation: + // Both methods should be supported. Method 1 should be preferred + // when calling parse with parsers defined inline. Method 2 should + // be preferred when a parser expression is assigned to a rule<>, + // thereby making the type of the rule<> independent of the skip + // parser used. I imagine a syntax like: + // rule<> r = skip(space)[A >> B >> C] + template<typename FwdIter, typename Rule, typename Skipper> + bool parse(FwdIter begin, FwdIter end, Rule const &rule, Skipper const &skipper) + { + // make sure the rule corresponds to the Spirit grammar: + BOOST_MPL_ASSERT((proto::matches<Rule, SpiritGrammar>)); + + //// Method 1: pass skip parser in the context structure. + //spirit_context<FwdIter, Skipper> ctx(begin, end, skipper); + //return proto::eval(rule, ctx); + + // Method 2: Embed skip parser via tree transformation. + spirit_context<FwdIter> ctx(begin, end); + return proto::eval(spirit2::skip(skipper)[rule], ctx); + } + +}} + +using namespace boost; +using namespace spirit2; + +void test_toy_spirit() +{ + std::string str("abcd"); + + // This will fail: + BOOST_CHECK(!spirit2::parse(str.begin(), str.end() + , char_ >> char_('a'))); + + // This will succeed: + BOOST_CHECK(spirit2::parse(str.begin(), str.end() + , char_ >> char_('b') >> char_ >> 'd')); + + // This will succeed: + BOOST_CHECK(spirit2::parse(str.begin(), str.end() + , 'a' >> ('c' >> char_ | 'b' >> char_('d') | 'b' >> char_('c')) >> 'd')); + + // This will succeed: + BOOST_CHECK(spirit2::parse(str.begin(), str.end() + , *(char_ - 'd'))); + + // This will succeed: + BOOST_CHECK(spirit2::parse(str.begin(), str.end() + , no_case[char_('A') >> 'B' >> "CD"])); + + // This will succeed: + BOOST_CHECK(spirit2::parse(str.begin(), str.end() + , no_case[*char_('A','Z')])); + + literal<char> a = lit('a'); + literal<char const *> bcd = lit("bcd"); + + // This will succeed: + BOOST_CHECK(spirit2::parse(str.begin(), str.end() + , +~~a >> no_case[bcd])); + + // Scanner Business: R.I.P. :-) + str = "a b cd"; + BOOST_CHECK(spirit2::parse(str.begin(), str.end() + , char_('a') >> 'b' >> 'c' >> 'd', space >> space)); + +} + +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 proto and and toy spirit-2"); + + test->add(BOOST_TEST_CASE(&test_toy_spirit)); + + return test; +} diff --git a/src/boost/libs/proto/test/toy_spirit2.cpp b/src/boost/libs/proto/test/toy_spirit2.cpp new file mode 100644 index 00000000..a0f246f3 --- /dev/null +++ b/src/boost/libs/proto/test/toy_spirit2.cpp @@ -0,0 +1,466 @@ +/////////////////////////////////////////////////////////////////////////////// +// toy_spirit3.cpp +// +// 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 <cctype> +#include <string> +#include <cstring> +#include <iomanip> +#include <iostream> +#include <boost/assert.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/utility/result_of.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/proto/core.hpp> +#include <boost/proto/transform.hpp> +#include <boost/fusion/include/for_each.hpp> +#include <boost/fusion/include/fold.hpp> +#include <boost/fusion/include/cons.hpp> +#include <boost/fusion/include/any.hpp> +#include <boost/test/unit_test.hpp> + +namespace boost +{ + // global tags + struct char_tag {}; + struct space_tag {}; + + // global primitives + proto::terminal<char_tag>::type const char_ = {{}}; + proto::terminal<space_tag>::type const space = {{}}; + + using proto::lit; + using proto::literal; +} + +namespace boost { namespace spirit2 +{ + namespace utility + { + inline bool char_icmp(char ch, char lo, char hi) + { + return ch == lo || ch == hi; + } + + template<typename FwdIter> + inline bool string_cmp(char const *sz, FwdIter &begin, FwdIter end) + { + FwdIter tmp = begin; + for(; *sz; ++tmp, ++sz) + if(tmp == end || *tmp != *sz) + return false; + begin = tmp; + return true; + } + + template<typename FwdIter> + inline bool string_icmp(std::string const &str, FwdIter &begin, FwdIter end) + { + BOOST_ASSERT(0 == str.size() % 2); + FwdIter tmp = begin; + std::string::const_iterator istr = str.begin(), estr = str.end(); + for(; istr != estr; ++tmp, istr += 2) + if(tmp == end || (*tmp != *istr && *tmp != *(istr+1))) + return false; + begin = tmp; + return true; + } + + inline bool in_range(char ch, char lo, char hi) + { + return ch >= lo && ch <= hi; + } + + inline bool in_irange(char ch, char lo, char hi) + { + return in_range(ch, lo, hi) + || in_range(std::tolower(ch), lo, hi) + || in_range(std::toupper(ch), lo, hi); + } + + inline std::string to_istr(char const *sz) + { + std::string res; + res.reserve(std::strlen(sz) * 2); + for(; *sz; ++sz) + { + res.push_back(std::tolower(*sz)); + res.push_back(std::toupper(*sz)); + } + return res; + } + } // namespace utility + + template<typename List> + struct alternate + { + explicit alternate(List const &list) + : elems(list) + {} + List elems; + }; + + template<typename List> + struct sequence + { + explicit sequence(List const &list) + : elems(list) + {} + List elems; + }; + + struct char_range + : std::pair<char, char> + { + char_range(char from, char to) + : std::pair<char, char>(from, to) + {} + }; + + struct ichar + { + ichar(char ch) + : lo_(std::tolower(ch)) + , hi_(std::toupper(ch)) + {} + + char lo_, hi_; + }; + + struct istr + { + istr(char const *sz) + : str_(utility::to_istr(sz)) + {} + + std::string str_; + }; + + struct ichar_range + : std::pair<char, char> + { + ichar_range(char from, char to) + : std::pair<char, char>(from, to) + {} + }; + + // The no-case directive + struct no_case_tag {}; + + struct True : mpl::true_ {}; + + /////////////////////////////////////////////////////////////////////////////// + /// Begin Spirit grammar here + /////////////////////////////////////////////////////////////////////////////// + namespace grammar + { + using namespace proto; + using namespace fusion; + + struct SpiritExpr; + + struct AnyChar + : terminal<char_tag> + {}; + + struct CharLiteral + : terminal<char> + {}; + + struct NTBSLiteral + : terminal<char const *> + {}; + + struct CharParser + : proto::function<AnyChar, CharLiteral> + {}; + + struct CharRangeParser + : proto::function<AnyChar, CharLiteral, CharLiteral> + {}; + + struct NoCase + : terminal<no_case_tag> + {}; + + // The data determines the case-sensitivity of the terminals + typedef _data _icase; + + // Ugh, would be nice to find a work-around for this: + #if BOOST_WORKAROUND(BOOST_MSVC, == 1310) + #define _value(x) call<_value(x)> + #define True() make<True()> + #endif + + // Extract the child from terminals + struct SpiritTerminal + : or_< + when< AnyChar, _value > + , when< CharLiteral, if_<_icase, ichar(_value), _value> > + , when< CharParser, if_<_icase, ichar(_value(_child1)), _value(_child1)> > // char_('a') + , when< NTBSLiteral, if_<_icase, istr(_value), char const*(_value)> > + , when< CharRangeParser, if_<_icase + , ichar_range(_value(_child1), _value(_child2)) + , char_range(_value(_child1), _value(_child2))> > // char_('a','z') + > + {}; + + struct FoldToList + : reverse_fold_tree<_, nil(), cons<SpiritExpr, _state>(SpiritExpr, _state)> + {}; + + // sequence rule folds all >>'s together into a list + // and wraps the result in a sequence<> wrapper + struct SpiritSequence + : when< shift_right<SpiritExpr, SpiritExpr>, sequence<FoldToList>(FoldToList) > + {}; + + // alternate rule folds all |'s together into a list + // and wraps the result in a alternate<> wrapper + struct SpiritAlternate + : when< bitwise_or<SpiritExpr, SpiritExpr>, alternate<FoldToList>(FoldToList) > + {}; + + // Directives such as no_case are handled here + struct SpiritDirective + : when< subscript<NoCase, SpiritExpr>, SpiritExpr(_right, _state, True()) > + {}; + + // A SpiritExpr is an alternate, a sequence, a directive or a terminal + struct SpiritExpr + : or_< + SpiritSequence + , SpiritAlternate + , SpiritDirective + , SpiritTerminal + > + {}; + + } // namespace grammar + + using grammar::SpiritExpr; + using grammar::NoCase; + + /////////////////////////////////////////////////////////////////////////////// + /// End SpiritExpr + /////////////////////////////////////////////////////////////////////////////// + + // Globals + NoCase::type const no_case = {{}}; + + template<typename Iterator> + struct parser; + + template<typename Iterator> + struct fold_alternate + { + parser<Iterator> const &parse; + + explicit fold_alternate(parser<Iterator> const &p) + : parse(p) + {} + + template<typename T> + bool operator ()(T const &t) const + { + Iterator tmp = this->parse.first; + if(this->parse(t)) + return true; + this->parse.first = tmp; + return false; + } + }; + + template<typename Iterator> + struct fold_sequence + { + parser<Iterator> const &parse; + + explicit fold_sequence(parser<Iterator> const &p) + : parse(p) + {} + + typedef bool result_type; + + template<typename T> + bool operator ()(bool success, T const &t) const + { + return success && this->parse(t); + } + }; + + template<typename Iterator> + struct parser + { + mutable Iterator first; + Iterator second; + + parser(Iterator begin, Iterator end) + : first(begin) + , second(end) + {} + + bool done() const + { + return this->first == this->second; + } + + template<typename List> + bool operator ()(alternate<List> const &alternates) const + { + return fusion::any(alternates.elems, fold_alternate<Iterator>(*this)); + } + + template<typename List> + bool operator ()(sequence<List> const &sequence) const + { + return fusion::fold(sequence.elems, true, fold_sequence<Iterator>(*this)); + } + + bool operator ()(char_tag ch) const + { + if(this->done()) + return false; + ++this->first; + return true; + } + + bool operator ()(char ch) const + { + if(this->done() || ch != *this->first) + return false; + ++this->first; + return true; + } + + bool operator ()(ichar ich) const + { + if(this->done() || !utility::char_icmp(*this->first, ich.lo_, ich.hi_)) + return false; + ++this->first; + return true; + } + + bool operator ()(char const *sz) const + { + return utility::string_cmp(sz, this->first, this->second); + } + + bool operator ()(istr const &s) const + { + return utility::string_icmp(s.str_, this->first, this->second); + } + + bool operator ()(char_range rng) const + { + if(this->done() || !utility::in_range(*this->first, rng.first, rng.second)) + return false; + ++this->first; + return true; + } + + bool operator ()(ichar_range rng) const + { + if(this->done() || !utility::in_irange(*this->first, rng.first, rng.second)) + return false; + ++this->first; + return true; + } + }; + + template<typename Rule, typename Iterator> + typename enable_if<proto::matches< Rule, SpiritExpr >, bool >::type + parse_impl(Rule const &rule, Iterator begin, Iterator end) + { + mpl::false_ is_case_sensitive; + parser<Iterator> parse_fun(begin, end); + return parse_fun(SpiritExpr()(rule, proto::ignore(), is_case_sensitive)); + } + + // 2nd overload provides a short error message for invalid rules + template<typename Rule, typename Iterator> + typename disable_if<proto::matches< Rule, SpiritExpr >, bool >::type + parse_impl(Rule const &rule, Iterator begin, Iterator end) + { + BOOST_MPL_ASSERT((proto::matches<Rule, SpiritExpr>)); + return false; + } + + // parse() converts rule literals to proto expressions if necessary + // and dispatches to parse_impl + template<typename Rule, typename Iterator> + bool parse(Rule const &rule, Iterator begin, Iterator end) + { + return parse_impl(proto::as_expr(rule), begin, end); + } + +}} + +void test_toy_spirit3() +{ + using boost::spirit2::no_case; + using boost::char_; + std::string hello("abcd"); + + BOOST_CHECK( + boost::spirit2::parse( + "abcd" + , hello.begin() + , hello.end() + ) + ); + + BOOST_CHECK( + boost::spirit2::parse( + char_ >> char_('b') >> 'c' >> char_ + , hello.begin() + , hello.end() + ) + ); + + BOOST_CHECK( + !boost::spirit2::parse( + char_ >> char_('b') >> 'c' >> 'D' + , hello.begin() + , hello.end() + ) + ); + + BOOST_CHECK( + boost::spirit2::parse( + char_ >> char_('b') >> 'c' >> 'e' + | char_ >> no_case[char_('B') >> "C" >> char_('D','Z')] + , hello.begin() + , hello.end() + ) + ); + + std::string nest_alt_input("abd"); + BOOST_CHECK( + boost::spirit2::parse( + char_('a') + >> ( char_('b') + | char_('c') + ) + >> char_('d') + , nest_alt_input.begin() + , nest_alt_input.end() + ) + ); +} + +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 proto, grammars and tree transforms"); + + test->add(BOOST_TEST_CASE(&test_toy_spirit3)); + + return test; +} |