summaryrefslogtreecommitdiff
path: root/boost/python/converter/arg_from_python.hpp
blob: e2edce7e1c5043c75df41de215da3f2115f83903 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
// Copyright David Abrahams 2002.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef ARG_FROM_PYTHON_DWA2002127_HPP
# define ARG_FROM_PYTHON_DWA2002127_HPP

# include <boost/python/detail/prefix.hpp>
# include <boost/python/converter/from_python.hpp>
# include <boost/python/detail/indirect_traits.hpp>
# include <boost/type_traits/transform_traits.hpp>
# include <boost/type_traits/cv_traits.hpp>
# include <boost/python/converter/rvalue_from_python_data.hpp>
# include <boost/mpl/eval_if.hpp>
# include <boost/mpl/if.hpp>
# include <boost/mpl/identity.hpp>
# include <boost/mpl/and.hpp>
# include <boost/mpl/or.hpp>
# include <boost/mpl/not.hpp>
# include <boost/python/converter/registry.hpp>
# include <boost/python/converter/registered.hpp>
# include <boost/python/converter/registered_pointee.hpp>
# include <boost/python/detail/void_ptr.hpp>
# include <boost/python/back_reference.hpp>
# include <boost/python/detail/referent_storage.hpp>
# include <boost/python/converter/obj_mgr_arg_from_python.hpp>

namespace boost { namespace python
{
  template <class T> struct arg_from_python;
}}

// This header defines Python->C++ function argument converters,
// parametrized on the argument type.

namespace boost { namespace python { namespace converter {

//
// lvalue converters
//
//   These require that an lvalue of the type U is stored somewhere in
//   the Python object being converted.

// Used when T == U*const&
template <class T>
struct pointer_cref_arg_from_python
{
    typedef T result_type;
    
    pointer_cref_arg_from_python(PyObject*);
    T operator()() const;
    bool convertible() const;
    
 private: // storage for a U*
    // needed because not all compilers will let us declare U* as the
    // return type of operator() -- we return U*const& instead
    typename python::detail::referent_storage<T>::type m_result;
};

// Base class for pointer and reference converters
struct arg_lvalue_from_python_base
{
 public: // member functions
    arg_lvalue_from_python_base(void* result);
    bool convertible() const;
    
 protected: // member functions
    void*const& result() const;
    
 private: // data members
    void* m_result;
};

// Used when T == U* 
template <class T>
struct pointer_arg_from_python : arg_lvalue_from_python_base
{
    typedef T result_type;
    
    pointer_arg_from_python(PyObject*);
    T operator()() const;
};

// Used when T == U& and (T != V const& or T == W volatile&)
template <class T>
struct reference_arg_from_python : arg_lvalue_from_python_base
{
    typedef T result_type;
    
    reference_arg_from_python(PyObject*);
    T operator()() const;
};

// ===================

//
// rvalue converters
//
//   These require only that an object of type T can be created from
//   the given Python object, but not that the T object exist
//   somewhere in storage.
//

// Used when T is a plain value (non-pointer, non-reference) type or
// a (non-volatile) const reference to a plain value type.
template <class T>
struct arg_rvalue_from_python
{
    typedef typename boost::add_reference<
        T
        // We can't add_const here, or it would be impossible to pass
        // auto_ptr<U> args from Python to C++
    >::type result_type;
    
    arg_rvalue_from_python(PyObject*);
    bool convertible() const;

# if BOOST_MSVC < 1301 || _MSC_FULL_VER > 13102196
    typename arg_rvalue_from_python<T>::
# endif 
    result_type operator()();
    
 private:
    rvalue_from_python_data<result_type> m_data;
    PyObject* m_source;
};


// ==================

// Converts to a (PyObject*,T) bundle, for when you need a reference
// back to the Python object
template <class T>
struct back_reference_arg_from_python
    : boost::python::arg_from_python<typename T::type>
{
    typedef T result_type;
    
    back_reference_arg_from_python(PyObject*);
    T operator()();
 private:
    typedef boost::python::arg_from_python<typename T::type> base;
    PyObject* m_source;
};


// ==================

template <class C, class T, class F>
struct if_2
{
    typedef typename mpl::eval_if<C, mpl::identity<T>, F>::type type;
};

// This metafunction selects the appropriate arg_from_python converter
// type for an argument of type T.
template <class T>
struct select_arg_from_python
{
    typedef typename if_2<
        is_object_manager<T>
      , object_manager_value_arg_from_python<T>
      , if_2<
            is_reference_to_object_manager<T>
          , object_manager_ref_arg_from_python<T>
          , if_2<
                is_pointer<T>
              , pointer_arg_from_python<T>
              , if_2<
                    mpl::and_<
                        indirect_traits::is_reference_to_pointer<T>
                      , indirect_traits::is_reference_to_const<T>
                      , mpl::not_<indirect_traits::is_reference_to_volatile<T> >
                        >
                  , pointer_cref_arg_from_python<T>
                  , if_2<
                        mpl::or_<
                            indirect_traits::is_reference_to_non_const<T>
                          , indirect_traits::is_reference_to_volatile<T>
                        >
                      , reference_arg_from_python<T>
                      , mpl::if_<
                            boost::python::is_back_reference<T>
                          , back_reference_arg_from_python<T>
                          , arg_rvalue_from_python<T>
                        >
                    >
                >
            >
        >
    >::type type;
};

// ==================

//
// implementations
//

// arg_lvalue_from_python_base
//
inline arg_lvalue_from_python_base::arg_lvalue_from_python_base(void* result)
    : m_result(result)
{
}

inline bool arg_lvalue_from_python_base::convertible() const
{
    return m_result != 0;
}

inline void*const& arg_lvalue_from_python_base::result() const
{
    return m_result;
}

// pointer_cref_arg_from_python
//
namespace detail
{
  // null_ptr_reference -- a function returning a reference to a null
  // pointer of type U. Needed so that extractors for T*const& can
  // convert Python's None.
  template <class T>
  struct null_ptr_owner
  {
      static T value;
  };
  template <class T> T null_ptr_owner<T>::value = 0;
  
  template <class U>
  inline U& null_ptr_reference(U&(*)())
  {
      return null_ptr_owner<U>::value;
  }
}

template <class T>
inline pointer_cref_arg_from_python<T>::pointer_cref_arg_from_python(PyObject* p)
{
    // T == U*const&: store a U* in the m_result storage. Nonzero
    // indicates success.  If find returns nonzero, it's a pointer to
    // a U object.
    python::detail::write_void_ptr_reference(
        m_result.bytes
        , p == Py_None ? p : converter::get_lvalue_from_python(p, registered_pointee<T>::converters)
        , (T(*)())0);
}

template <class T>
inline bool pointer_cref_arg_from_python<T>::convertible() const
{
    return python::detail::void_ptr_to_reference(m_result.bytes, (T(*)())0) != 0;
}
template <class T>
inline T pointer_cref_arg_from_python<T>::operator()() const
{
    return (*(void**)m_result.bytes == Py_None)  // None ==> 0
        ? detail::null_ptr_reference((T(*)())0)
        // Otherwise, return a U*const& to the m_result storage.
        : python::detail::void_ptr_to_reference(m_result.bytes, (T(*)())0);
}

// pointer_arg_from_python
//
template <class T>
inline pointer_arg_from_python<T>::pointer_arg_from_python(PyObject* p)
    : arg_lvalue_from_python_base(
        p == Py_None ? p : converter::get_lvalue_from_python(p, registered_pointee<T>::converters))
{
}

template <class T>
inline T pointer_arg_from_python<T>::operator()() const
{
    return (result() == Py_None) ? 0 : T(result());
}

// reference_arg_from_python
//
template <class T>
inline reference_arg_from_python<T>::reference_arg_from_python(PyObject* p)
    : arg_lvalue_from_python_base(converter::get_lvalue_from_python(p,registered<T>::converters))
{
}

template <class T>
inline T reference_arg_from_python<T>::operator()() const
{
    return python::detail::void_ptr_to_reference(result(), (T(*)())0);
}


// arg_rvalue_from_python
//
template <class T>
inline arg_rvalue_from_python<T>::arg_rvalue_from_python(PyObject* obj)
    : m_data(converter::rvalue_from_python_stage1(obj, registered<T>::converters))
    , m_source(obj)
{
}

template <class T>
inline bool arg_rvalue_from_python<T>::convertible() const
{
    return m_data.stage1.convertible != 0;
}

template <class T>
inline typename arg_rvalue_from_python<T>::result_type
arg_rvalue_from_python<T>::operator()()
{
    if (m_data.stage1.construct != 0)
        m_data.stage1.construct(m_source, &m_data.stage1);
    
    return python::detail::void_ptr_to_reference(m_data.stage1.convertible, (result_type(*)())0);
}

// back_reference_arg_from_python
//
template <class T>
back_reference_arg_from_python<T>::back_reference_arg_from_python(PyObject* x)
  : base(x), m_source(x)
{
}

template <class T>
inline T
back_reference_arg_from_python<T>::operator()()
{
    return T(m_source, base::operator()());
}

}}} // namespace boost::python::converter

#endif // ARG_FROM_PYTHON_DWA2002127_HPP