1 // Copyright David Abrahams and Nikolay Mladenov 2003.
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 RETURN_ARG_DWA2003719_HPP
6 # define RETURN_ARG_DWA2003719_HPP
7 # include <boost/python/default_call_policies.hpp>
8 # include <boost/python/detail/none.hpp>
9 # include <boost/python/detail/value_arg.hpp>
10 
11 # include <boost/type_traits/add_reference.hpp>
12 # include <boost/type_traits/add_const.hpp>
13 
14 # include <boost/mpl/int.hpp>
15 
16 # include <boost/static_assert.hpp>
17 # include <boost/python/refcount.hpp>
18 
19 # include <cstddef>
20 
21 namespace boost { namespace python {
22 
23 namespace detail
24 {
25   template <std::size_t>
26   struct return_arg_pos_argument_must_be_positive
27 # if defined(__GNUC__) && __GNUC__ >= 3 || defined(__EDG__)
28   {}
29 # endif
30   ;
31 
32   struct return_none
33   {
34       template <class T> struct apply
35       {
36           struct type
37           {
convertibleboost::python::detail::return_none::apply::type38               static bool convertible()
39               {
40                   return true;
41               }
42 
operator ()boost::python::detail::return_none::apply::type43               PyObject *operator()( typename value_arg<T>::type ) const
44               {
45                   return none();
46               }
47           };
48       };
49   };
50 }
51 
52 template <
53     std::size_t arg_pos=1
54   , class Base = default_call_policies
55 >
56 struct return_arg : Base
57 {
58  private:
59     BOOST_STATIC_CONSTANT(bool, legal = arg_pos > 0);
60 
61  public:
62     typedef typename mpl::if_c<
63         legal
64         , detail::return_none
65         , detail::return_arg_pos_argument_must_be_positive<arg_pos>
66         // we could default to the base result_converter in case or
67         // arg_pos==0 since return arg 0 means return result, but I
68         // think it is better to issue an error instead, cause it can
69         // lead to confusions
70     >::type result_converter;
71 
72     template <class ArgumentPackage>
postcallboost::python::return_arg73     static PyObject* postcall(ArgumentPackage const& args, PyObject* result)
74     {
75         // In case of arg_pos == 0 we could simply return Base::postcall,
76         // but this is redundant
77         BOOST_STATIC_ASSERT(arg_pos > 0);
78 
79         result = Base::postcall(args,result);
80         if (!result)
81             return 0;
82         Py_DECREF(result);
83         return incref( detail::get(mpl::int_<arg_pos-1>(),args) );
84     }
85 };
86 
87 template <
88     class Base = default_call_policies
89     >
90 struct return_self
91   : return_arg<1,Base>
92 {};
93 
94 }} // namespace boost::python
95 
96 #endif // RETURN_ARG_DWA2003719_HPP
97