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
14namespace boost { namespace python {
15
16namespace detail
17{
18 template <std::size_t N>
19 struct get_prev
20 {
21 template <class ArgumentPackage>
22 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>
32 static PyObject* execute(ArgumentPackage const&, PyObject* zeroth)
33 {
34 return zeroth;
35 }
36 };
37}
38template <
39 std::size_t custodian
40 , std::size_t ward
41 , class BasePolicy_ = default_call_policies
42>
43struct 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>
50 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
79template <std::size_t custodian, std::size_t ward, class BasePolicy_ = default_call_policies>
80struct with_custodian_and_ward_postcall : BasePolicy_
81{
82 BOOST_STATIC_ASSERT(custodian != ward);
83
84 template <class ArgumentPackage>
85 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)(a: custodian, b: 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

source code of boost/boost/python/with_custodian_and_ward.hpp