1 // Copyright David Abrahams 2002. 2 // Distributed under the Boost Software License, Version 1.0. (See 3 // accompanying file LICENSE_1_0.txt or copy at 4 // http://www.boost.org/LICENSE_1_0.txt) 5 #ifndef WITH_CUSTODIAN_AND_WARD_DWA2002131_HPP 6 # define WITH_CUSTODIAN_AND_WARD_DWA2002131_HPP 7 8 # include <boost/python/detail/prefix.hpp> 9 10 # include <boost/python/default_call_policies.hpp> 11 # include <boost/python/object/life_support.hpp> 12 # include <algorithm> 13 14 namespace boost { namespace python { 15 16 namespace detail 17 { 18 template <std::size_t N> 19 struct get_prev 20 { 21 template <class ArgumentPackage> executeboost::python::detail::get_prev22 static PyObject* execute(ArgumentPackage const& args, PyObject* = 0) 23 { 24 int const pre_n = static_cast<int>(N) - 1; // separate line is gcc-2.96 workaround 25 return detail::get(mpl::int_<pre_n>(), args); 26 } 27 }; 28 template <> 29 struct get_prev<0> 30 { 31 template <class ArgumentPackage> executeboost::python::detail::get_prev32 static PyObject* execute(ArgumentPackage const&, PyObject* zeroth) 33 { 34 return zeroth; 35 } 36 }; 37 } 38 template < 39 std::size_t custodian 40 , std::size_t ward 41 , class BasePolicy_ = default_call_policies 42 > 43 struct with_custodian_and_ward : BasePolicy_ 44 { 45 BOOST_STATIC_ASSERT(custodian != ward); 46 BOOST_STATIC_ASSERT(custodian > 0); 47 BOOST_STATIC_ASSERT(ward > 0); 48 49 template <class ArgumentPackage> precallboost::python::with_custodian_and_ward50 static bool precall(ArgumentPackage const& args_) 51 { 52 unsigned arity_ = detail::arity(args_); 53 if (custodian > arity_ || ward > arity_) 54 { 55 PyErr_SetString( 56 PyExc_IndexError 57 , "boost::python::with_custodian_and_ward: argument index out of range" 58 ); 59 return false; 60 } 61 62 PyObject* patient = detail::get_prev<ward>::execute(args_); 63 PyObject* nurse = detail::get_prev<custodian>::execute(args_); 64 65 PyObject* life_support = python::objects::make_nurse_and_patient(nurse, patient); 66 if (life_support == 0) 67 return false; 68 69 bool result = BasePolicy_::precall(args_); 70 71 if (!result) { 72 Py_DECREF(life_support); 73 } 74 75 return result; 76 } 77 }; 78 79 template <std::size_t custodian, std::size_t ward, class BasePolicy_ = default_call_policies> 80 struct with_custodian_and_ward_postcall : BasePolicy_ 81 { 82 BOOST_STATIC_ASSERT(custodian != ward); 83 84 template <class ArgumentPackage> postcallboost::python::with_custodian_and_ward_postcall85 static PyObject* postcall(ArgumentPackage const& args_, PyObject* result) 86 { 87 std::size_t arity_ = detail::arity(args_); 88 // check if either custodian or ward exceeds the arity 89 // (this weird formulation avoids "always false" warnings 90 // for arity_ = 0) 91 if ( (std::max)(custodian, ward) > arity_ ) 92 { 93 PyErr_SetString( 94 PyExc_IndexError 95 , "boost::python::with_custodian_and_ward_postcall: argument index out of range" 96 ); 97 return 0; 98 } 99 100 PyObject* patient = detail::get_prev<ward>::execute(args_, result); 101 PyObject* nurse = detail::get_prev<custodian>::execute(args_, result); 102 103 if (nurse == 0) return 0; 104 105 result = BasePolicy_::postcall(args_, result); 106 if (result == 0) 107 return 0; 108 109 if (python::objects::make_nurse_and_patient(nurse, patient) == 0) 110 { 111 Py_XDECREF(result); 112 return 0; 113 } 114 return result; 115 } 116 }; 117 118 119 }} // namespace boost::python 120 121 #endif // WITH_CUSTODIAN_AND_WARD_DWA2002131_HPP 122