Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/libs/python/src/converter/builtin_converters.cpp @ 29

Last change on this file since 29 was 29, checked in by landauf, 16 years ago

updated boost from 1_33_1 to 1_34_1

File size: 12.7 KB
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
6#include <boost/python/handle.hpp>
7#include <boost/python/type_id.hpp>
8#include <boost/python/errors.hpp>
9#include <boost/python/refcount.hpp>
10
11#include <boost/python/detail/config.hpp>
12#include <boost/python/detail/wrap_python.hpp>
13
14#include <boost/python/converter/builtin_converters.hpp>
15#include <boost/python/converter/rvalue_from_python_data.hpp>
16#include <boost/python/converter/registry.hpp>
17#include <boost/python/converter/registrations.hpp>
18#include <boost/python/converter/shared_ptr_deleter.hpp>
19
20#include <boost/cast.hpp>
21#include <string>
22#include <complex>
23
24namespace boost { namespace python { namespace converter {
25
26shared_ptr_deleter::shared_ptr_deleter(handle<> owner)
27    : owner(owner)
28{}
29
30shared_ptr_deleter::~shared_ptr_deleter() {}
31
32void shared_ptr_deleter::operator()(void const*)
33{
34    owner.reset();
35}
36
37namespace
38{
39  // An lvalue conversion function which extracts a char const* from a
40  // Python String.
41  void* convert_to_cstring(PyObject* obj)
42  {
43      return PyString_Check(obj) ? PyString_AsString(obj) : 0;
44  }
45
46  // Given a target type and a SlotPolicy describing how to perform a
47  // given conversion, registers from_python converters which use the
48  // SlotPolicy to extract the type.
49  template <class T, class SlotPolicy>
50  struct slot_rvalue_from_python
51  {
52   public:
53      slot_rvalue_from_python()
54      {
55          registry::insert(
56              &slot_rvalue_from_python<T,SlotPolicy>::convertible
57              , &slot_rvalue_from_python<T,SlotPolicy>::construct
58              , type_id<T>()
59              );
60      }
61     
62   private:
63      static void* convertible(PyObject* obj)
64      {
65          unaryfunc* slot = SlotPolicy::get_slot(obj);
66          return slot && *slot ? slot : 0;
67      }
68
69      static void construct(PyObject* obj, rvalue_from_python_stage1_data* data)
70      {
71          // Get the (intermediate) source object
72          unaryfunc creator = *static_cast<unaryfunc*>(data->convertible);
73          handle<> intermediate(creator(obj));
74
75          // Get the location in which to construct
76          void* storage = ((rvalue_from_python_storage<T>*)data)->storage.bytes;
77# ifdef _MSC_VER
78#  pragma warning(push)
79#  pragma warning(disable:4244)
80# endif
81          new (storage) T( SlotPolicy::extract(intermediate.get()) );
82         
83# ifdef _MSC_VER
84#  pragma warning(pop)
85# endif
86          // record successful construction
87          data->convertible = storage;
88      }
89  };
90
91  // A SlotPolicy for extracting signed integer types from Python objects
92  struct signed_int_rvalue_from_python_base
93  {
94      static unaryfunc* get_slot(PyObject* obj)
95      {
96          PyNumberMethods* number_methods = obj->ob_type->tp_as_number;
97          if (number_methods == 0)
98              return 0;
99
100          return (PyInt_Check(obj) || PyLong_Check(obj))
101              ? &number_methods->nb_int : 0;
102      }
103  };
104
105  template <class T>
106  struct signed_int_rvalue_from_python : signed_int_rvalue_from_python_base
107  {
108      static T extract(PyObject* intermediate)
109      {
110          long x = PyInt_AsLong(intermediate);
111          if (PyErr_Occurred())
112              throw_error_already_set();
113          return numeric_cast<T>(x);
114      }
115  };
116
117  // identity_unaryfunc/py_object_identity -- manufacture a unaryfunc
118  // "slot" which just returns its argument.
119  extern "C" PyObject* identity_unaryfunc(PyObject* x)
120  {
121      Py_INCREF(x);
122      return x;
123  }
124  unaryfunc py_object_identity = identity_unaryfunc;
125
126  // A SlotPolicy for extracting unsigned integer types from Python objects
127  struct unsigned_int_rvalue_from_python_base
128  {
129      static unaryfunc* get_slot(PyObject* obj)
130      {
131          PyNumberMethods* number_methods = obj->ob_type->tp_as_number;
132          if (number_methods == 0)
133              return 0;
134
135          return (PyInt_Check(obj) || PyLong_Check(obj))
136              ? &py_object_identity : 0;
137      }
138  };
139
140  template <class T>
141  struct unsigned_int_rvalue_from_python : unsigned_int_rvalue_from_python_base
142  {
143      static T extract(PyObject* intermediate)
144      {
145          return numeric_cast<T>(
146              PyLong_Check(intermediate)
147              ? PyLong_AsUnsignedLong(intermediate)
148              : PyInt_AS_LONG(intermediate));
149      }
150  };
151
152// Checking Python's macro instead of Boost's - we don't seem to get
153// the config right all the time. Furthermore, Python's is defined
154// when long long is absent but __int64 is present.
155 
156#ifdef HAVE_LONG_LONG
157  // A SlotPolicy for extracting long long types from Python objects
158
159  struct long_long_rvalue_from_python_base
160  {
161      static unaryfunc* get_slot(PyObject* obj)
162      {
163          PyNumberMethods* number_methods = obj->ob_type->tp_as_number;
164          if (number_methods == 0)
165              return 0;
166
167          // Return the identity conversion slot to avoid creating a
168          // new object. We'll handle that in the extract function
169          if (PyInt_Check(obj))
170              return &number_methods->nb_int;
171          else if (PyLong_Check(obj))
172              return &number_methods->nb_long;
173          else
174              return 0;
175      }
176  };
177 
178  struct long_long_rvalue_from_python : long_long_rvalue_from_python_base
179  {
180      static BOOST_PYTHON_LONG_LONG extract(PyObject* intermediate)
181      {
182          if (PyInt_Check(intermediate))
183          {
184              return PyInt_AS_LONG(intermediate);
185          }
186          else
187          {
188              BOOST_PYTHON_LONG_LONG result = PyLong_AsLongLong(intermediate);
189             
190              if (PyErr_Occurred())
191                  throw_error_already_set();
192
193              return result;
194          }
195      }
196  };
197
198  struct unsigned_long_long_rvalue_from_python : long_long_rvalue_from_python_base
199  {
200      static unsigned BOOST_PYTHON_LONG_LONG extract(PyObject* intermediate)
201      {
202          if (PyInt_Check(intermediate))
203          {
204              return numeric_cast<unsigned BOOST_PYTHON_LONG_LONG>(PyInt_AS_LONG(intermediate));
205          }
206          else
207          {
208              unsigned BOOST_PYTHON_LONG_LONG result = PyLong_AsUnsignedLongLong(intermediate);
209             
210              if (PyErr_Occurred())
211                  throw_error_already_set();
212
213              return result;
214          }
215      }
216  };
217#endif
218
219  // A SlotPolicy for extracting bool from a Python object
220  struct bool_rvalue_from_python
221  {
222      static unaryfunc* get_slot(PyObject* obj)
223      {
224          return obj == Py_None || PyInt_Check(obj) ? &py_object_identity : 0;
225      }
226     
227      static bool extract(PyObject* intermediate)
228      {
229          return PyObject_IsTrue(intermediate);
230      }
231  };
232
233  // A SlotPolicy for extracting floating types from Python objects.
234  struct float_rvalue_from_python
235  {
236      static unaryfunc* get_slot(PyObject* obj)
237      {
238          PyNumberMethods* number_methods = obj->ob_type->tp_as_number;
239          if (number_methods == 0)
240              return 0;
241
242          // For integer types, return the tp_int conversion slot to avoid
243          // creating a new object. We'll handle that below
244          if (PyInt_Check(obj))
245              return &number_methods->nb_int;
246
247          return (PyLong_Check(obj) || PyFloat_Check(obj))
248              ? &number_methods->nb_float : 0;
249      }
250     
251      static double extract(PyObject* intermediate)
252      {
253          if (PyInt_Check(intermediate))
254          {
255              return PyInt_AS_LONG(intermediate);
256          }
257          else
258          {
259              return PyFloat_AS_DOUBLE(intermediate);
260          }
261      }
262  };
263
264  // A SlotPolicy for extracting C++ strings from Python objects.
265  struct string_rvalue_from_python
266  {
267      // If the underlying object is "string-able" this will succeed
268      static unaryfunc* get_slot(PyObject* obj)
269      {
270          return (PyString_Check(obj))
271              ? &obj->ob_type->tp_str : 0;
272      };
273
274      // Remember that this will be used to construct the result object
275      static std::string extract(PyObject* intermediate)
276      {
277          return std::string(PyString_AsString(intermediate),PyString_Size(intermediate));
278      }
279  };
280
281#if defined(Py_USING_UNICODE) && !defined(BOOST_NO_STD_WSTRING)
282  // encode_string_unaryfunc/py_encode_string -- manufacture a unaryfunc
283  // "slot" which encodes a Python string using the default encoding
284  extern "C" PyObject* encode_string_unaryfunc(PyObject* x)
285  {
286      return PyUnicode_FromEncodedObject( x, 0, 0 );
287  }
288  unaryfunc py_encode_string = encode_string_unaryfunc;
289
290  // A SlotPolicy for extracting C++ strings from Python objects.
291  struct wstring_rvalue_from_python
292  {
293      // If the underlying object is "string-able" this will succeed
294      static unaryfunc* get_slot(PyObject* obj)
295      {
296          return PyUnicode_Check(obj)
297              ? &py_object_identity
298            : PyString_Check(obj)
299              ? &py_encode_string
300            : 0;
301      };
302
303      // Remember that this will be used to construct the result object
304      static std::wstring extract(PyObject* intermediate)
305      {
306          std::wstring result(::PyObject_Length(intermediate), L' ');
307          if (!result.empty())
308          {
309              int err = PyUnicode_AsWideChar(
310                  (PyUnicodeObject *)intermediate
311                , &result[0]
312                , result.size());
313
314              if (err == -1)
315                  throw_error_already_set();
316          }
317          return result;
318      }
319  };
320#endif
321
322  struct complex_rvalue_from_python
323  {
324      static unaryfunc* get_slot(PyObject* obj)
325      {
326          if (PyComplex_Check(obj))
327              return &py_object_identity;
328          else
329              return float_rvalue_from_python::get_slot(obj);
330      }
331     
332      static std::complex<double> extract(PyObject* intermediate)
333      {
334          if (PyComplex_Check(intermediate))
335          {
336              return std::complex<double>(
337                  PyComplex_RealAsDouble(intermediate)
338                  , PyComplex_ImagAsDouble(intermediate));
339          }
340          else if (PyInt_Check(intermediate))
341          {
342              return PyInt_AS_LONG(intermediate);
343          }
344          else
345          {
346              return PyFloat_AS_DOUBLE(intermediate);
347          }
348      }
349  };
350} 
351
352BOOST_PYTHON_DECL PyObject* do_return_to_python(char x)
353{
354    return PyString_FromStringAndSize(&x, 1);
355}
356 
357BOOST_PYTHON_DECL PyObject* do_return_to_python(char const* x)
358{
359    return x ? PyString_FromString(x) : boost::python::detail::none();
360}
361 
362BOOST_PYTHON_DECL PyObject* do_return_to_python(PyObject* x)
363{
364    return x ? x : boost::python::detail::none();
365}
366 
367BOOST_PYTHON_DECL PyObject* do_arg_to_python(PyObject* x)
368{
369    if (x == 0)
370        return boost::python::detail::none();
371     
372    Py_INCREF(x);
373    return x;
374}
375
376#define REGISTER_INT_CONVERTERS(signedness, U)                          \
377        slot_rvalue_from_python<                                        \
378                signedness U                                            \
379                ,signedness##_int_rvalue_from_python<signedness U>      \
380         >()
381
382#define REGISTER_INT_CONVERTERS2(U)             \
383        REGISTER_INT_CONVERTERS(signed, U);     \
384        REGISTER_INT_CONVERTERS(unsigned, U) 
385
386void initialize_builtin_converters()
387{
388    // booleans
389    slot_rvalue_from_python<bool,bool_rvalue_from_python>();
390
391    // integer types
392    REGISTER_INT_CONVERTERS2(char);
393    REGISTER_INT_CONVERTERS2(short);
394    REGISTER_INT_CONVERTERS2(int);
395    REGISTER_INT_CONVERTERS2(long);
396   
397// using Python's macro instead of Boost's - we don't seem to get the
398// config right all the time.
399# ifdef HAVE_LONG_LONG
400    slot_rvalue_from_python<signed BOOST_PYTHON_LONG_LONG,long_long_rvalue_from_python>();
401    slot_rvalue_from_python<unsigned BOOST_PYTHON_LONG_LONG,unsigned_long_long_rvalue_from_python>();
402# endif
403       
404    // floating types
405    slot_rvalue_from_python<float,float_rvalue_from_python>();
406    slot_rvalue_from_python<double,float_rvalue_from_python>();
407    slot_rvalue_from_python<long double,float_rvalue_from_python>();
408   
409    slot_rvalue_from_python<std::complex<float>,complex_rvalue_from_python>();
410    slot_rvalue_from_python<std::complex<double>,complex_rvalue_from_python>();
411    slot_rvalue_from_python<std::complex<long double>,complex_rvalue_from_python>();
412   
413    // Add an lvalue converter for char which gets us char const*
414    registry::insert(convert_to_cstring,type_id<char>());
415
416    // Register by-value converters to std::string, std::wstring
417#if defined(Py_USING_UNICODE) && !defined(BOOST_NO_STD_WSTRING)
418    slot_rvalue_from_python<std::wstring, wstring_rvalue_from_python>();
419# endif
420    slot_rvalue_from_python<std::string, string_rvalue_from_python>();
421}
422
423}}} // namespace boost::python::converter
Note: See TracBrowser for help on using the repository browser.