]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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> | |
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 | } | |
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> | |
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 | ||
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> | |
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)(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 |