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 PY_FUNCTION_DWA200286_HPP
6 # define PY_FUNCTION_DWA200286_HPP
7 
8 # include <boost/python/detail/signature.hpp>
9 # include <boost/detail/workaround.hpp>
10 # include <boost/mpl/size.hpp>
11 # include <memory>
12 
13 namespace boost { namespace python { namespace objects {
14 
15 // This type is used as a "generalized Python callback", wrapping the
16 // function signature:
17 //
18 //      PyObject* (PyObject* args, PyObject* keywords)
19 
20 struct BOOST_PYTHON_DECL py_function_impl_base
21 {
22     virtual ~py_function_impl_base();
23     virtual PyObject* operator()(PyObject*, PyObject*) = 0;
24     virtual unsigned min_arity() const = 0;
25     virtual unsigned max_arity() const;
26     virtual python::detail::py_func_sig_info signature() const = 0;
27 };
28 
29 template <class Caller>
30 struct caller_py_function_impl : py_function_impl_base
31 {
caller_py_function_implboost::python::objects::caller_py_function_impl32     caller_py_function_impl(Caller const& caller)
33         : m_caller(caller)
34     {}
35 
operator ()boost::python::objects::caller_py_function_impl36     PyObject* operator()(PyObject* args, PyObject* kw)
37     {
38         return m_caller(args, kw);
39     }
40 
min_arityboost::python::objects::caller_py_function_impl41     virtual unsigned min_arity() const
42     {
43         return m_caller.min_arity();
44     }
45 
signatureboost::python::objects::caller_py_function_impl46     virtual python::detail::py_func_sig_info signature() const
47     {
48         return m_caller.signature();
49     }
50 
51  private:
52     Caller m_caller;
53 };
54 
55 template <class Caller, class Sig>
56 struct signature_py_function_impl : py_function_impl_base
57 {
signature_py_function_implboost::python::objects::signature_py_function_impl58     signature_py_function_impl(Caller const& caller)
59         : m_caller(caller)
60     {}
61 
operator ()boost::python::objects::signature_py_function_impl62     PyObject* operator()(PyObject* args, PyObject* kw)
63     {
64         return m_caller(args, kw);
65     }
66 
min_arityboost::python::objects::signature_py_function_impl67     virtual unsigned min_arity() const
68     {
69         return mpl::size<Sig>::value - 1;
70     }
71 
signatureboost::python::objects::signature_py_function_impl72     virtual python::detail::py_func_sig_info signature() const
73     {
74         python::detail::signature_element const* sig = python::detail::signature<Sig>::elements();
75         python::detail::py_func_sig_info res = {sig, sig};
76         return  res;
77     }
78 
79  private:
80     Caller m_caller;
81 };
82 
83 template <class Caller, class Sig>
84 struct full_py_function_impl : py_function_impl_base
85 {
full_py_function_implboost::python::objects::full_py_function_impl86     full_py_function_impl(Caller const& caller, unsigned min_arity, unsigned max_arity)
87       : m_caller(caller)
88       , m_min_arity(min_arity)
89       , m_max_arity(max_arity > min_arity ? max_arity : min_arity)
90     {}
91 
operator ()boost::python::objects::full_py_function_impl92     PyObject* operator()(PyObject* args, PyObject* kw)
93     {
94         return m_caller(args, kw);
95     }
96 
min_arityboost::python::objects::full_py_function_impl97     virtual unsigned min_arity() const
98     {
99         return m_min_arity;
100     }
101 
max_arityboost::python::objects::full_py_function_impl102     virtual unsigned max_arity() const
103     {
104         return m_max_arity;
105     }
106 
signatureboost::python::objects::full_py_function_impl107     virtual python::detail::py_func_sig_info signature() const
108     {
109         python::detail::signature_element const* sig = python::detail::signature<Sig>::elements();
110         python::detail::py_func_sig_info res = {sig, sig};
111         return  res;
112     }
113 
114  private:
115     Caller m_caller;
116     unsigned m_min_arity;
117     unsigned m_max_arity;
118 };
119 
120 struct py_function
121 {
122     template <class Caller>
py_functionboost::python::objects::py_function123     py_function(Caller const& caller)
124         : m_impl(new caller_py_function_impl<Caller>(caller))
125     {}
126 
127     template <class Caller, class Sig>
py_functionboost::python::objects::py_function128     py_function(Caller const& caller, Sig)
129       : m_impl(new signature_py_function_impl<Caller, Sig>(caller))
130     {}
131 
132     template <class Caller, class Sig>
py_functionboost::python::objects::py_function133     py_function(Caller const& caller, Sig, int min_arity, int max_arity = 0)
134       : m_impl(new full_py_function_impl<Caller, Sig>(caller, min_arity, max_arity))
135     {}
136 
py_functionboost::python::objects::py_function137     py_function(py_function const& rhs)
138 #if defined(BOOST_NO_CXX11_SMART_PTR)
139       : m_impl(rhs.m_impl)
140 #else
141       : m_impl(std::move(rhs.m_impl))
142 #endif
143     {}
144 
operator ()boost::python::objects::py_function145     PyObject* operator()(PyObject* args, PyObject* kw) const
146     {
147         return (*m_impl)(args, kw);
148     }
149 
min_arityboost::python::objects::py_function150     unsigned min_arity() const
151     {
152         return m_impl->min_arity();
153     }
154 
max_arityboost::python::objects::py_function155     unsigned max_arity() const
156     {
157         return m_impl->max_arity();
158     }
159 
signatureboost::python::objects::py_function160     python::detail::signature_element const* signature() const
161     {
162         return m_impl->signature().signature;
163     }
164 
get_return_typeboost::python::objects::py_function165     python::detail::signature_element const& get_return_type() const
166     {
167         return *m_impl->signature().ret;
168     }
169 
170  private:
171 #if defined(BOOST_NO_CXX11_SMART_PTR)
172     mutable std::auto_ptr<py_function_impl_base> m_impl;
173 #else
174     mutable std::unique_ptr<py_function_impl_base> m_impl;
175 #endif
176 };
177 
178 }}} // namespace boost::python::objects
179 
180 #endif // PY_FUNCTION_DWA200286_HPP
181