| // Copyright David Abrahams 2002. |
| // 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) |
| #ifndef WITH_CUSTODIAN_AND_WARD_DWA2002131_HPP |
| # define WITH_CUSTODIAN_AND_WARD_DWA2002131_HPP |
| |
| # include <boost/python/detail/prefix.hpp> |
| |
| # include <boost/python/default_call_policies.hpp> |
| # include <boost/python/object/life_support.hpp> |
| # include <algorithm> |
| |
| namespace boost { namespace python { |
| |
| namespace detail |
| { |
| template <std::size_t N> |
| struct get_prev |
| { |
| template <class ArgumentPackage> |
| static PyObject* execute(ArgumentPackage const& args, PyObject* = 0) |
| { |
| int const pre_n = static_cast<int>(N) - 1; // separate line is gcc-2.96 workaround |
| return detail::get(mpl::int_<pre_n>(), args); |
| } |
| }; |
| template <> |
| struct get_prev<0> |
| { |
| template <class ArgumentPackage> |
| static PyObject* execute(ArgumentPackage const&, PyObject* zeroth) |
| { |
| return zeroth; |
| } |
| }; |
| } |
| template < |
| std::size_t custodian |
| , std::size_t ward |
| , class BasePolicy_ = default_call_policies |
| > |
| struct with_custodian_and_ward : BasePolicy_ |
| { |
| BOOST_STATIC_ASSERT(custodian != ward); |
| BOOST_STATIC_ASSERT(custodian > 0); |
| BOOST_STATIC_ASSERT(ward > 0); |
| |
| template <class ArgumentPackage> |
| static bool precall(ArgumentPackage const& args_) |
| { |
| unsigned arity_ = detail::arity(args_); |
| if (custodian > arity_ || ward > arity_) |
| { |
| PyErr_SetString( |
| PyExc_IndexError |
| , "boost::python::with_custodian_and_ward: argument index out of range" |
| ); |
| return false; |
| } |
| |
| PyObject* patient = detail::get_prev<ward>::execute(args_); |
| PyObject* nurse = detail::get_prev<custodian>::execute(args_); |
| |
| PyObject* life_support = python::objects::make_nurse_and_patient(nurse, patient); |
| if (life_support == 0) |
| return false; |
| |
| bool result = BasePolicy_::precall(args_); |
| |
| if (!result) { |
| Py_DECREF(life_support); |
| } |
| |
| return result; |
| } |
| }; |
| |
| template <std::size_t custodian, std::size_t ward, class BasePolicy_ = default_call_policies> |
| struct with_custodian_and_ward_postcall : BasePolicy_ |
| { |
| BOOST_STATIC_ASSERT(custodian != ward); |
| |
| template <class ArgumentPackage> |
| static PyObject* postcall(ArgumentPackage const& args_, PyObject* result) |
| { |
| std::size_t arity_ = detail::arity(args_); |
| #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) |
| if ( custodian > arity_ || ward > arity_ ) |
| #else |
| // check if either custodian or ward exceeds the arity |
| // (this weird formulation avoids "always false" warnings |
| // for arity_ = 0) |
| if ( (std::max)(custodian, ward) > arity_ ) |
| #endif |
| { |
| PyErr_SetString( |
| PyExc_IndexError |
| , "boost::python::with_custodian_and_ward_postcall: argument index out of range" |
| ); |
| return 0; |
| } |
| |
| PyObject* patient = detail::get_prev<ward>::execute(args_, result); |
| PyObject* nurse = detail::get_prev<custodian>::execute(args_, result); |
| |
| if (nurse == 0) return 0; |
| |
| result = BasePolicy_::postcall(args_, result); |
| if (result == 0) |
| return 0; |
| |
| if (python::objects::make_nurse_and_patient(nurse, patient) == 0) |
| { |
| Py_XDECREF(result); |
| return 0; |
| } |
| return result; |
| } |
| }; |
| |
| |
| }} // namespace boost::python |
| |
| #endif // WITH_CUSTODIAN_AND_WARD_DWA2002131_HPP |