Chris@16: // Copyright David Abrahams 2002. Chris@16: // Distributed under the Boost Software License, Version 1.0. (See Chris@16: // accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: #ifndef WITH_CUSTODIAN_AND_WARD_DWA2002131_HPP Chris@16: # define WITH_CUSTODIAN_AND_WARD_DWA2002131_HPP Chris@16: Chris@16: # include Chris@16: Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: Chris@16: namespace boost { namespace python { Chris@16: Chris@16: namespace detail Chris@16: { Chris@16: template Chris@16: struct get_prev Chris@16: { Chris@16: template Chris@16: static PyObject* execute(ArgumentPackage const& args, PyObject* = 0) Chris@16: { Chris@16: int const pre_n = static_cast(N) - 1; // separate line is gcc-2.96 workaround Chris@16: return detail::get(mpl::int_(), args); Chris@16: } Chris@16: }; Chris@16: template <> Chris@16: struct get_prev<0> Chris@16: { Chris@16: template Chris@16: static PyObject* execute(ArgumentPackage const&, PyObject* zeroth) Chris@16: { Chris@16: return zeroth; Chris@16: } Chris@16: }; Chris@16: } Chris@16: template < Chris@16: std::size_t custodian Chris@16: , std::size_t ward Chris@16: , class BasePolicy_ = default_call_policies Chris@16: > Chris@16: struct with_custodian_and_ward : BasePolicy_ Chris@16: { Chris@16: BOOST_STATIC_ASSERT(custodian != ward); Chris@16: BOOST_STATIC_ASSERT(custodian > 0); Chris@16: BOOST_STATIC_ASSERT(ward > 0); Chris@16: Chris@16: template Chris@16: static bool precall(ArgumentPackage const& args_) Chris@16: { Chris@16: unsigned arity_ = detail::arity(args_); Chris@16: if (custodian > arity_ || ward > arity_) Chris@16: { Chris@16: PyErr_SetString( Chris@16: PyExc_IndexError Chris@16: , "boost::python::with_custodian_and_ward: argument index out of range" Chris@16: ); Chris@16: return false; Chris@16: } Chris@16: Chris@16: PyObject* patient = detail::get_prev::execute(args_); Chris@16: PyObject* nurse = detail::get_prev::execute(args_); Chris@16: Chris@16: PyObject* life_support = python::objects::make_nurse_and_patient(nurse, patient); Chris@16: if (life_support == 0) Chris@16: return false; Chris@16: Chris@16: bool result = BasePolicy_::precall(args_); Chris@16: Chris@16: if (!result) { Chris@16: Py_DECREF(life_support); Chris@16: } Chris@16: Chris@16: return result; Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct with_custodian_and_ward_postcall : BasePolicy_ Chris@16: { Chris@16: BOOST_STATIC_ASSERT(custodian != ward); Chris@16: Chris@16: template Chris@16: static PyObject* postcall(ArgumentPackage const& args_, PyObject* result) Chris@16: { Chris@16: std::size_t arity_ = detail::arity(args_); Chris@16: #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) Chris@16: if ( custodian > arity_ || ward > arity_ ) Chris@16: #else Chris@16: // check if either custodian or ward exceeds the arity Chris@16: // (this weird formulation avoids "always false" warnings Chris@16: // for arity_ = 0) Chris@16: if ( (std::max)(custodian, ward) > arity_ ) Chris@16: #endif Chris@16: { Chris@16: PyErr_SetString( Chris@16: PyExc_IndexError Chris@16: , "boost::python::with_custodian_and_ward_postcall: argument index out of range" Chris@16: ); Chris@16: return 0; Chris@16: } Chris@16: Chris@16: PyObject* patient = detail::get_prev::execute(args_, result); Chris@16: PyObject* nurse = detail::get_prev::execute(args_, result); Chris@16: Chris@16: if (nurse == 0) return 0; Chris@16: Chris@16: result = BasePolicy_::postcall(args_, result); Chris@16: if (result == 0) Chris@16: return 0; Chris@16: Chris@16: if (python::objects::make_nurse_and_patient(nurse, patient) == 0) Chris@16: { Chris@16: Py_XDECREF(result); Chris@16: return 0; Chris@16: } Chris@16: return result; Chris@16: } Chris@16: }; Chris@16: Chris@16: Chris@16: }} // namespace boost::python Chris@16: Chris@16: #endif // WITH_CUSTODIAN_AND_WARD_DWA2002131_HPP