source: NonGTP/Boost/boost/python/with_custodian_and_ward.hpp @ 857

Revision 857, 3.4 KB checked in by igarcia, 18 years ago (diff)
Line 
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        return result;
75    }
76};
77
78template <std::size_t custodian, std::size_t ward, class BasePolicy_ = default_call_policies>
79struct with_custodian_and_ward_postcall : BasePolicy_
80{
81    BOOST_STATIC_ASSERT(custodian != ward);
82   
83    template <class ArgumentPackage>
84    static PyObject* postcall(ArgumentPackage const& args_, PyObject* result)
85    {
86        std::size_t arity_ = detail::arity(args_);
87        if ( custodian > arity_ || ward > arity_ )
88        {
89            PyErr_SetString(
90                PyExc_IndexError
91              , "boost::python::with_custodian_and_ward_postcall: argument index out of range"
92            );
93            return 0;
94        }
95       
96        PyObject* patient = detail::get_prev<ward>::execute(args_, result);
97        PyObject* nurse = detail::get_prev<custodian>::execute(args_, result);
98
99        if (nurse == 0) return 0;
100   
101        result = BasePolicy_::postcall(args_, result);
102        if (result == 0)
103            return 0;
104           
105        if (python::objects::make_nurse_and_patient(nurse, patient) == 0)
106        {
107            Py_XDECREF(result);
108            return 0;
109        }
110        return result;
111    }
112};
113
114
115}} // namespace boost::python
116
117#endif // WITH_CUSTODIAN_AND_WARD_DWA2002131_HPP
Note: See TracBrowser for help on using the repository browser.