diff options
Diffstat (limited to 'src/boost/libs/proto/test/mem_ptr.cpp')
-rw-r--r-- | src/boost/libs/proto/test/mem_ptr.cpp | 303 |
1 files changed, 303 insertions, 0 deletions
diff --git a/src/boost/libs/proto/test/mem_ptr.cpp b/src/boost/libs/proto/test/mem_ptr.cpp new file mode 100644 index 000000000..5326c665b --- /dev/null +++ b/src/boost/libs/proto/test/mem_ptr.cpp @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// mem_ptr.hpp +// +// Copyright 2009 Eric Niebler. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/mpl/print.hpp> +#include <iostream> +#include <boost/shared_ptr.hpp> +#include <boost/proto/proto.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/utility/result_of.hpp> +#include <boost/test/unit_test.hpp> + +namespace proto = boost::proto; +using proto::_; + +struct evaluator + : proto::when<_, proto::_default<evaluator> > +{}; + +template<typename Ret, typename Expr> +void assert_result_type(Expr &) +{ + // check that the return type as calculated by the _default transform + // is correct. + BOOST_MPL_ASSERT(( + boost::is_same< + Ret + , typename boost::result_of<evaluator(Expr &)>::type + > + )); + + // check that the return type as calculated by the default_context + // is correct. + BOOST_MPL_ASSERT(( + boost::is_same< + Ret + , typename boost::result_of<proto::functional::eval(Expr &, proto::default_context &)>::type + > + )); +} + +/////////////////////////////////////////////////////////////////////////////// +struct S +{ + S() : x(-42) {} + int x; +}; + +// like a normal terminal except with an operator() that can +// accept non-const lvalues (Proto's only accepts const lvalues) +template<typename T, typename Dummy = proto::is_proto_expr> +struct my_terminal +{ + typedef typename proto::terminal<T>::type my_terminal_base; + BOOST_PROTO_BASIC_EXTENDS(my_terminal_base, my_terminal, proto::default_domain) + + template<typename A0> + typename proto::result_of::make_expr<proto::tag::function, my_terminal const &, A0 &>::type const + operator()(A0 &a0) const + { + return proto::make_expr<proto::tag::function>(boost::ref(*this), boost::ref(a0)); + } + + template<typename A0> + typename proto::result_of::make_expr<proto::tag::function, my_terminal const &, A0 const &>::type const + operator()(A0 const &a0) const + { + return proto::make_expr<proto::tag::function>(boost::ref(*this), boost::ref(a0)); + } +}; + +my_terminal<int S::*> test1 = {{ &S::x }}; + +// Some tests with the default transform +void test_refs_transform() +{ + S s; + BOOST_REQUIRE_EQUAL(s.x, -42); + + // Check that evaluating a memptr invocation with a + // non-const lvalue argument yields the member as a + // non-const lvalue + assert_result_type<int &>(test1(s)); + evaluator()(test1(s)) = 0; + BOOST_CHECK_EQUAL(s.x, 0); + + // Ditto for reference_wrappers + assert_result_type<int &>(test1(boost::ref(s))); + evaluator()(test1(boost::ref(s))) = 42; + BOOST_CHECK_EQUAL(s.x, 42); + + // Check that evaluating a memptr invocation with a + // const lvalue argument yields the member as a + // const lvalue + S const &rcs = s; + assert_result_type<int const &>(test1(rcs)); + int const &s_x = evaluator()(test1(rcs)); + BOOST_CHECK_EQUAL(&s.x, &s_x); +} + +// Some tests with the default context +void test_refs_context() +{ + proto::default_context ctx; + S s; + BOOST_REQUIRE_EQUAL(s.x, -42); + + // Check that evaluating a memptr invocation with a + // non-const lvalue argument yields the member as a + // non-const lvalue + assert_result_type<int &>(test1(s)); + proto::eval(test1(s), ctx) = 0; + BOOST_CHECK_EQUAL(s.x, 0); + + // Ditto for reference_wrappers + assert_result_type<int &>(test1(boost::ref(s))); + proto::eval(test1(boost::ref(s)), ctx) = 42; + BOOST_CHECK_EQUAL(s.x, 42); + + // Check that evaluating a memptr invocation with a + // const lvalue argument yields the member as a + // const lvalue + S const &rcs = s; + assert_result_type<int const &>(test1(rcs)); + int const &s_x = proto::eval(test1(rcs), ctx); + BOOST_CHECK_EQUAL(&s.x, &s_x); +} + +void test_ptrs_transform() +{ + S s; + BOOST_REQUIRE_EQUAL(s.x, -42); + + // Check that evaluating a memptr invocation with a + // pointer to a non-const argument yields the member as a + // non-const lvalue + assert_result_type<int &>(test1(&s)); + evaluator()(test1(&s)) = 0; + BOOST_CHECK_EQUAL(s.x, 0); + + S* ps = &s; + assert_result_type<int &>(test1(ps)); + evaluator()(test1(ps)) = 42; + BOOST_CHECK_EQUAL(s.x, 42); + + boost::shared_ptr<S> const sp(new S); + BOOST_REQUIRE_EQUAL(sp->x, -42); + + // Ditto for shared_ptr (which hook the get_pointer() + // customization point) + assert_result_type<int &>(test1(sp)); + evaluator()(test1(sp)) = 0; + BOOST_CHECK_EQUAL(sp->x, 0); + + // Check that evaluating a memptr invocation with a + // const lvalue argument yields the member as a + // const lvalue + S const &rcs = s; + assert_result_type<int const &>(test1(&rcs)); + int const &s_x0 = evaluator()(test1(&rcs)); + BOOST_CHECK_EQUAL(&s.x, &s_x0); + + S const *pcs = &s; + assert_result_type<int const &>(test1(pcs)); + int const &s_x1 = evaluator()(test1(pcs)); + BOOST_CHECK_EQUAL(&s.x, &s_x1); + + boost::shared_ptr<S const> spc(new S); + BOOST_REQUIRE_EQUAL(spc->x, -42); + + assert_result_type<int const &>(test1(spc)); + int const &s_x2 = evaluator()(test1(spc)); + BOOST_CHECK_EQUAL(&spc->x, &s_x2); +} + +void test_ptrs_context() +{ + proto::default_context ctx; + S s; + BOOST_REQUIRE_EQUAL(s.x, -42); + + // Check that evaluating a memptr invocation with a + // pointer to a non-const argument yields the member as a + // non-const lvalue + assert_result_type<int &>(test1(&s)); + proto::eval(test1(&s), ctx) = 0; + BOOST_CHECK_EQUAL(s.x, 0); + + S* ps = &s; + assert_result_type<int &>(test1(ps)); + proto::eval(test1(ps), ctx) = 42; + BOOST_CHECK_EQUAL(s.x, 42); + + boost::shared_ptr<S> const sp(new S); + BOOST_REQUIRE_EQUAL(sp->x, -42); + + // Ditto for shared_ptr (which hook the get_pointer() + // customization point) + assert_result_type<int &>(test1(sp)); + proto::eval(test1(sp), ctx) = 0; + BOOST_CHECK_EQUAL(sp->x, 0); + + // Check that evaluating a memptr invocation with a + // const lvalue argument yields the member as a + // const lvalue + S const &rcs = s; + assert_result_type<int const &>(test1(&rcs)); + int const &s_x0 = proto::eval(test1(&rcs), ctx); + BOOST_CHECK_EQUAL(&s.x, &s_x0); + + S const *pcs = &s; + assert_result_type<int const &>(test1(pcs)); + int const &s_x1 = proto::eval(test1(pcs), ctx); + BOOST_CHECK_EQUAL(&s.x, &s_x1); + + boost::shared_ptr<S const> spc(new S); + BOOST_REQUIRE_EQUAL(spc->x, -42); + + assert_result_type<int const &>(test1(spc)); + int const &s_x2 = proto::eval(test1(spc), ctx); + BOOST_CHECK_EQUAL(&spc->x, &s_x2); +} + +/////////////////////////////////////////////////////////////////////////////// +struct T +{ + int x; +}; + +proto::terminal<int T::*>::type test2 = { &T::x }; + +int const *get_pointer(T const &t) +{ + return &t.x; +} + +void with_get_pointer_transform() +{ + T t; + evaluator()(test2(t)); +} + +/////////////////////////////////////////////////////////////////////////////// +template<typename T> +struct dumb_ptr +{ + dumb_ptr(T *p_) : p(p_) {} + + friend T const *get_pointer(dumb_ptr const &p) + { + return p.p; + } + + T *p; +}; + +struct U : dumb_ptr<U> +{ + U() : dumb_ptr<U>(this), x(42) {} + int x; +}; + +my_terminal<U *dumb_ptr<U>::*> U_p = {{&U::p}}; +my_terminal<int U::*> U_x = {{&U::x}}; + +void potentially_ambiguous_transform() +{ + U u; + + // This should yield a non-const reference to a pointer-to-const + U *&up = evaluator()(U_p(u)); + BOOST_CHECK_EQUAL(&up, &u.p); + + // This should yield a non-const reference to a pointer-to-const + int &ux = evaluator()(U_x(u)); + BOOST_CHECK_EQUAL(&ux, &u.x); +} + + +using namespace boost::unit_test; +/////////////////////////////////////////////////////////////////////////////// +// init_unit_test_suite +// +test_suite* init_unit_test_suite( int argc, char* argv[] ) +{ + test_suite *test = BOOST_TEST_SUITE("test handling of member pointers by the default transform and default contexts"); + + test->add(BOOST_TEST_CASE(&test_refs_transform)); + test->add(BOOST_TEST_CASE(&test_refs_context)); + + test->add(BOOST_TEST_CASE(&test_ptrs_transform)); + test->add(BOOST_TEST_CASE(&test_ptrs_context)); + + test->add(BOOST_TEST_CASE(&with_get_pointer_transform)); + + test->add(BOOST_TEST_CASE(&potentially_ambiguous_transform)); + + return test; +} |