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/example | |
parent | Initial commit. (diff) | |
download | ceph-483eb2f56657e8e7f419ab1a4fab8dce9ade8609.tar.xz ceph-483eb2f56657e8e7f419ab1a4fab8dce9ade8609.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/example')
-rw-r--r-- | src/boost/libs/proto/example/Jamfile.v2 | 87 | ||||
-rw-r--r-- | src/boost/libs/proto/example/calc1.cpp | 68 | ||||
-rw-r--r-- | src/boost/libs/proto/example/calc2.cpp | 103 | ||||
-rw-r--r-- | src/boost/libs/proto/example/calc3.cpp | 154 | ||||
-rw-r--r-- | src/boost/libs/proto/example/external_transforms.cpp | 128 | ||||
-rw-r--r-- | src/boost/libs/proto/example/futures.cpp | 134 | ||||
-rw-r--r-- | src/boost/libs/proto/example/hello.cpp | 28 | ||||
-rw-r--r-- | src/boost/libs/proto/example/lambda.cpp | 17 | ||||
-rw-r--r-- | src/boost/libs/proto/example/lambda.hpp | 1730 | ||||
-rw-r--r-- | src/boost/libs/proto/example/lazy_vector.cpp | 142 | ||||
-rw-r--r-- | src/boost/libs/proto/example/map_assign.cpp | 136 | ||||
-rw-r--r-- | src/boost/libs/proto/example/mini_lambda.cpp | 263 | ||||
-rw-r--r-- | src/boost/libs/proto/example/mixed.cpp | 375 | ||||
-rw-r--r-- | src/boost/libs/proto/example/rgb.cpp | 102 | ||||
-rw-r--r-- | src/boost/libs/proto/example/tarray.cpp | 222 | ||||
-rw-r--r-- | src/boost/libs/proto/example/vec3.cpp | 184 | ||||
-rw-r--r-- | src/boost/libs/proto/example/vector.cpp | 241 | ||||
-rw-r--r-- | src/boost/libs/proto/example/virtual_member.cpp | 306 |
18 files changed, 4420 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; +} +//] |