sl@0: // Copyright David Abrahams 2002. sl@0: // Distributed under the Boost Software License, Version 1.0. (See sl@0: // accompanying file LICENSE_1_0.txt or copy at sl@0: // http://www.boost.org/LICENSE_1_0.txt) sl@0: #ifndef DATA_MEMBERS_DWA2002328_HPP sl@0: # define DATA_MEMBERS_DWA2002328_HPP sl@0: sl@0: # include sl@0: sl@0: # include sl@0: sl@0: # include sl@0: # include sl@0: # include sl@0: # include sl@0: sl@0: # include sl@0: sl@0: # include sl@0: # include sl@0: # include sl@0: sl@0: # include sl@0: # include sl@0: # include sl@0: sl@0: # if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3003)) sl@0: # include sl@0: # endif sl@0: sl@0: # include sl@0: # include sl@0: # include sl@0: sl@0: # include sl@0: sl@0: namespace boost { namespace python { sl@0: sl@0: // sl@0: // This file defines the make_getter and make_setter function sl@0: // families, which are responsible for turning pointers, references, sl@0: // and pointers-to-data-members into callable Python objects which sl@0: // can be used for attribute access on wrapped classes. sl@0: // sl@0: sl@0: namespace detail sl@0: { sl@0: sl@0: // A small function object which handles the getting and setting of sl@0: // data members. sl@0: template sl@0: struct member sl@0: { sl@0: public: sl@0: member(Data Class::*which) : m_which(which) {} sl@0: sl@0: Data& operator()(Class& c) const sl@0: { sl@0: return c.*m_which; sl@0: } sl@0: sl@0: void operator()(Class& c, typename value_arg::type d) const sl@0: { sl@0: c.*m_which = d; sl@0: } sl@0: private: sl@0: Data Class::*m_which; sl@0: }; sl@0: sl@0: // A small function object which handles the getting and setting of sl@0: // non-member objects. sl@0: template sl@0: struct datum sl@0: { sl@0: public: sl@0: datum(Data *which) : m_which(which) {} sl@0: sl@0: Data& operator()() const sl@0: { sl@0: return *m_which; sl@0: } sl@0: sl@0: void operator()(typename value_arg::type d) const sl@0: { sl@0: *m_which = d; sl@0: } sl@0: private: sl@0: Data *m_which; sl@0: }; sl@0: sl@0: // sl@0: // Helper metafunction for determining the default CallPolicy to use sl@0: // for attribute access. If T is a [reference to a] class type X sl@0: // whose conversion to python would normally produce a new copy of X sl@0: // in a wrapped X class instance (as opposed to types such as sl@0: // std::string, which are converted to native Python types, and sl@0: // smart pointer types which produce a wrapped class instance of the sl@0: // pointee type), to-python conversions will attempt to produce an sl@0: // object which refers to the original C++ object, rather than a sl@0: // copy. See default_member_getter_policy for rationale. sl@0: // sl@0: template sl@0: struct default_getter_by_ref sl@0: : mpl::and_< sl@0: mpl::bool_< sl@0: to_python_value< sl@0: typename value_arg::type sl@0: >::uses_registry sl@0: > sl@0: , indirect_traits::is_reference_to_class< sl@0: typename value_arg::type sl@0: > sl@0: > sl@0: { sl@0: }; sl@0: sl@0: // Metafunction computing the default CallPolicy to use for reading sl@0: // data members sl@0: // sl@0: // If it's a regular class type (not an object manager or other sl@0: // type for which we have to_python specializations, use sl@0: // return_internal_reference so that we can do things like sl@0: // x.y.z = 1 sl@0: // and get the right result. sl@0: template sl@0: struct default_member_getter_policy sl@0: : mpl::if_< sl@0: default_getter_by_ref sl@0: , return_internal_reference<> sl@0: , return_value_policy sl@0: > sl@0: {}; sl@0: sl@0: // Metafunction computing the default CallPolicy to use for reading sl@0: // non-member data. sl@0: template sl@0: struct default_datum_getter_policy sl@0: : mpl::if_< sl@0: default_getter_by_ref sl@0: , return_value_policy sl@0: , return_value_policy sl@0: > sl@0: {}; sl@0: sl@0: // sl@0: // make_getter helper function family -- These helpers to sl@0: // boost::python::make_getter are used to dispatch behavior. The sl@0: // third argument is a workaround for a CWPro8 partial ordering bug sl@0: // with pointers to data members. It should be convertible to sl@0: // mpl::true_ iff the first argument is a pointer-to-member, and sl@0: // mpl::false_ otherwise. The fourth argument is for compilers sl@0: // which don't support partial ordering at all and should always be sl@0: // passed 0L. sl@0: // sl@0: sl@0: #if BOOST_WORKAROUND(__EDG_VERSION__, <= 238) sl@0: template sl@0: inline object make_getter(D& d, P& p, mpl::false_, ...); sl@0: #endif sl@0: sl@0: // Handle non-member pointers with policies sl@0: template sl@0: inline object make_getter(D* d, Policies const& policies, mpl::false_, int) sl@0: { sl@0: return python::make_function( sl@0: detail::datum(d), policies, mpl::vector1() sl@0: ); sl@0: } sl@0: sl@0: // Handle non-member pointers without policies sl@0: template sl@0: inline object make_getter(D* d, not_specified, mpl::false_, long) sl@0: { sl@0: typedef typename default_datum_getter_policy::type policies; sl@0: return detail::make_getter(d, policies(), mpl::false_(), 0); sl@0: } sl@0: sl@0: // Handle pointers-to-members with policies sl@0: template sl@0: inline object make_getter(D C::*pm, Policies const& policies, mpl::true_, int) sl@0: { sl@0: #if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3003)) sl@0: typedef typename remove_cv::type Class; sl@0: #else sl@0: typedef C Class; sl@0: #endif sl@0: return python::make_function( sl@0: detail::member(pm) sl@0: , policies sl@0: , mpl::vector2() sl@0: ); sl@0: } sl@0: sl@0: // Handle pointers-to-members without policies sl@0: template sl@0: inline object make_getter(D C::*pm, not_specified, mpl::true_, long) sl@0: { sl@0: typedef typename default_member_getter_policy::type policies; sl@0: return detail::make_getter(pm, policies(), mpl::true_(), 0); sl@0: } sl@0: sl@0: // Handle references sl@0: template sl@0: inline object make_getter(D& d, P& p, mpl::false_, ...) sl@0: { sl@0: // Just dispatch to the handler for pointer types. sl@0: return detail::make_getter(&d, p, mpl::false_(), 0L); sl@0: } sl@0: sl@0: // sl@0: // make_setter helper function family -- These helpers to sl@0: // boost::python::make_setter are used to dispatch behavior. The sl@0: // third argument is for compilers which don't support partial sl@0: // ordering at all and should always be passed 0. sl@0: // sl@0: sl@0: sl@0: // Handle non-member pointers sl@0: template sl@0: inline object make_setter(D* p, Policies const& policies, mpl::false_, int) sl@0: { sl@0: return python::make_function( sl@0: detail::datum(p), policies, mpl::vector2() sl@0: ); sl@0: } sl@0: sl@0: // Handle pointers-to-members sl@0: template sl@0: inline object make_setter(D C::*pm, Policies const& policies, mpl::true_, int) sl@0: { sl@0: return python::make_function( sl@0: detail::member(pm) sl@0: , policies sl@0: , mpl::vector3() sl@0: ); sl@0: } sl@0: sl@0: // Handle references sl@0: template sl@0: inline object make_setter(D& x, Policies const& policies, mpl::false_, ...) sl@0: { sl@0: return detail::make_setter(&x, policies, mpl::false_(), 0L); sl@0: } sl@0: } sl@0: sl@0: // sl@0: // make_getter function family -- build a callable object which sl@0: // retrieves data through the first argument and is appropriate for sl@0: // use as the `get' function in Python properties . The second, sl@0: // policies argument, is optional. We need both D& and D const& sl@0: // overloads in order be able to handle rvalues. sl@0: // sl@0: template sl@0: inline object make_getter(D& d, Policies const& policies) sl@0: { sl@0: return detail::make_getter(d, policies, is_member_pointer(), 0L); sl@0: } sl@0: sl@0: template sl@0: inline object make_getter(D const& d, Policies const& policies) sl@0: { sl@0: return detail::make_getter(d, policies, is_member_pointer(), 0L); sl@0: } sl@0: sl@0: template sl@0: inline object make_getter(D& x) sl@0: { sl@0: detail::not_specified policy; sl@0: return detail::make_getter(x, policy, is_member_pointer(), 0L); sl@0: } sl@0: sl@0: # if !BOOST_WORKAROUND(__EDG_VERSION__, <= 238) && !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) sl@0: template sl@0: inline object make_getter(D const& d) sl@0: { sl@0: detail::not_specified policy; sl@0: return detail::make_getter(d, policy, is_member_pointer(), 0L); sl@0: } sl@0: # endif sl@0: sl@0: // sl@0: // make_setter function family -- build a callable object which sl@0: // writes data through the first argument and is appropriate for sl@0: // use as the `set' function in Python properties . The second, sl@0: // policies argument, is optional. We need both D& and D const& sl@0: // overloads in order be able to handle rvalues. sl@0: // sl@0: template sl@0: inline object make_setter(D& x, Policies const& policies) sl@0: { sl@0: return detail::make_setter(x, policies, is_member_pointer(), 0); sl@0: } sl@0: sl@0: template sl@0: inline object make_setter(D const& x, Policies const& policies) sl@0: { sl@0: return detail::make_setter(x, policies, is_member_pointer(), 0); sl@0: } sl@0: sl@0: template sl@0: inline object make_setter(D& x) sl@0: { sl@0: return detail::make_setter(x, default_call_policies(), is_member_pointer(), 0); sl@0: } sl@0: sl@0: # if !(BOOST_WORKAROUND(BOOST_MSVC, <= 1300) || BOOST_WORKAROUND(__EDG_VERSION__, <= 238)) sl@0: template sl@0: inline object make_setter(D const& x) sl@0: { sl@0: return detail::make_setter(x, default_call_policies(), is_member_pointer(), 0); sl@0: } sl@0: # endif sl@0: sl@0: }} // namespace boost::python sl@0: sl@0: #endif // DATA_MEMBERS_DWA2002328_HPP