• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <boost/python/converter/pytype_function.hpp>
20 
21 #include <boost/cast.hpp>
22 #include <string>
23 #include <complex>
24 
25 namespace boost { namespace python { namespace converter {
26 
shared_ptr_deleter(handle<> owner)27 shared_ptr_deleter::shared_ptr_deleter(handle<> owner)
28     : owner(owner)
29 {}
30 
~shared_ptr_deleter()31 shared_ptr_deleter::~shared_ptr_deleter() {}
32 
operator ()(void const *)33 void shared_ptr_deleter::operator()(void const*)
34 {
35     owner.reset();
36 }
37 
38 namespace
39 {
40 
41   // An lvalue conversion function which extracts a char const* from a
42   // Python String.
43 #if PY_VERSION_HEX < 0x03000000
convert_to_cstring(PyObject * obj)44   void* convert_to_cstring(PyObject* obj)
45   {
46       return PyString_Check(obj) ? PyString_AsString(obj) : 0;
47   }
48 #elif PY_VERSION_HEX < 0x03070000
49   void* convert_to_cstring(PyObject* obj)
50   {
51       return PyUnicode_Check(obj) ? _PyUnicode_AsString(obj) : 0;
52   }
53 #else
54   void* convert_to_cstring(PyObject* obj)
55   {
56       return PyUnicode_Check(obj) ? const_cast<void*>(reinterpret_cast<const void*>(_PyUnicode_AsString(obj))) : 0;
57   }
58 #endif
59 
60   // Given a target type and a SlotPolicy describing how to perform a
61   // given conversion, registers from_python converters which use the
62   // SlotPolicy to extract the type.
63   template <class T, class SlotPolicy>
64   struct slot_rvalue_from_python
65   {
66    public:
slot_rvalue_from_pythonboost::python::converter::__anonb96b74d40111::slot_rvalue_from_python67       slot_rvalue_from_python()
68       {
69           registry::insert(
70               &slot_rvalue_from_python<T,SlotPolicy>::convertible
71               , &slot_rvalue_from_python<T,SlotPolicy>::construct
72               , type_id<T>()
73               , &SlotPolicy::get_pytype
74               );
75       }
76 
77    private:
convertibleboost::python::converter::__anonb96b74d40111::slot_rvalue_from_python78       static void* convertible(PyObject* obj)
79       {
80           unaryfunc* slot = SlotPolicy::get_slot(obj);
81           return slot && *slot ? slot : 0;
82       }
83 
constructboost::python::converter::__anonb96b74d40111::slot_rvalue_from_python84       static void construct(PyObject* obj, rvalue_from_python_stage1_data* data)
85       {
86           // Get the (intermediate) source object
87           unaryfunc creator = *static_cast<unaryfunc*>(data->convertible);
88           handle<> intermediate(creator(obj));
89 
90           // Get the location in which to construct
91           void* storage = ((rvalue_from_python_storage<T>*)data)->storage.bytes;
92 # ifdef _MSC_VER
93 #  pragma warning(push)
94 #  pragma warning(disable:4244)
95 # endif
96           new (storage) T( SlotPolicy::extract(intermediate.get()) );
97 
98 # ifdef _MSC_VER
99 #  pragma warning(pop)
100 # endif
101           // record successful construction
102           data->convertible = storage;
103       }
104   };
105 
106   // identity_unaryfunc/py_object_identity -- manufacture a unaryfunc
107   // "slot" which just returns its argument.
identity_unaryfunc(PyObject * x)108   extern "C" PyObject* identity_unaryfunc(PyObject* x)
109   {
110       Py_INCREF(x);
111       return x;
112   }
113   unaryfunc py_object_identity = identity_unaryfunc;
114 
115 #if PY_VERSION_HEX >= 0x03000000
116   // As in Python 3 there is only one integer type, we can have much
117   // simplified logic.
118   // XXX(bhy) maybe the code will work with 2.6 or even 2.5?
119   struct int_rvalue_from_python_base
120   {
get_slotboost::python::converter::__anonb96b74d40111::int_rvalue_from_python_base121       static unaryfunc* get_slot(PyObject* obj)
122       {
123           return PyLong_Check(obj) ? &py_object_identity : 0;
124       }
get_pytypeboost::python::converter::__anonb96b74d40111::int_rvalue_from_python_base125       static PyTypeObject const* get_pytype() {return &PyLong_Type;}
126   };
127 
128   template <class T>
129   struct signed_int_rvalue_from_python : int_rvalue_from_python_base
130   {
extractboost::python::converter::__anonb96b74d40111::signed_int_rvalue_from_python131       static T extract(PyObject* intermediate)
132       {
133           long x = PyLong_AsLong(intermediate);
134           if (PyErr_Occurred())
135               throw_error_already_set();
136           return numeric_cast<T>(x);
137       }
138   };
139 
140   template <class T>
141   struct unsigned_int_rvalue_from_python : int_rvalue_from_python_base
142   {
extractboost::python::converter::__anonb96b74d40111::unsigned_int_rvalue_from_python143       static T extract(PyObject* intermediate)
144       {
145           unsigned long x = PyLong_AsUnsignedLong(intermediate);
146           if (PyErr_Occurred())
147               throw_error_already_set();
148           return numeric_cast<T>(x);
149       }
150   };
151 #else // PY_VERSION_HEX >= 0x03000000
152   // A SlotPolicy for extracting signed integer types from Python objects
153   struct signed_int_rvalue_from_python_base
154   {
get_slotboost::python::converter::__anonb96b74d40111::signed_int_rvalue_from_python_base155       static unaryfunc* get_slot(PyObject* obj)
156       {
157           PyNumberMethods* number_methods = obj->ob_type->tp_as_number;
158           if (number_methods == 0)
159               return 0;
160 
161           return (
162 #if PY_VERSION_HEX >= 0x02040000 && defined(BOOST_PYTHON_BOOL_INT_STRICT)
163           !PyBool_Check(obj) &&
164 #endif
165           (PyInt_Check(obj) || PyLong_Check(obj)))
166 
167         ? &number_methods->nb_int : 0;
168       }
get_pytypeboost::python::converter::__anonb96b74d40111::signed_int_rvalue_from_python_base169       static PyTypeObject const* get_pytype() { return &PyInt_Type;}
170   };
171 
172   template <class T>
173   struct signed_int_rvalue_from_python : signed_int_rvalue_from_python_base
174   {
extractboost::python::converter::__anonb96b74d40111::signed_int_rvalue_from_python175       static T extract(PyObject* intermediate)
176       {
177           long x = PyInt_AsLong(intermediate);
178           if (PyErr_Occurred())
179               throw_error_already_set();
180           return numeric_cast<T>(x);
181       }
182   };
183 
184   // A SlotPolicy for extracting unsigned integer types from Python objects
185   struct unsigned_int_rvalue_from_python_base
186   {
get_slotboost::python::converter::__anonb96b74d40111::unsigned_int_rvalue_from_python_base187       static unaryfunc* get_slot(PyObject* obj)
188       {
189           PyNumberMethods* number_methods = obj->ob_type->tp_as_number;
190           if (number_methods == 0)
191               return 0;
192 
193           return (
194 #if PY_VERSION_HEX >= 0x02040000 && defined(BOOST_PYTHON_BOOL_INT_STRICT)
195           !PyBool_Check(obj) &&
196 #endif
197           (PyInt_Check(obj) || PyLong_Check(obj)))
198               ? &py_object_identity : 0;
199       }
get_pytypeboost::python::converter::__anonb96b74d40111::unsigned_int_rvalue_from_python_base200       static PyTypeObject const* get_pytype() { return &PyInt_Type;}
201   };
202 
203   template <class T>
204   struct unsigned_int_rvalue_from_python : unsigned_int_rvalue_from_python_base
205   {
extractboost::python::converter::__anonb96b74d40111::unsigned_int_rvalue_from_python206       static T extract(PyObject* intermediate)
207       {
208           if (PyLong_Check(intermediate)) {
209               // PyLong_AsUnsignedLong() checks for negative overflow, so no
210               // need to check it here.
211               unsigned long result = PyLong_AsUnsignedLong(intermediate);
212               if (PyErr_Occurred())
213                   throw_error_already_set();
214               return numeric_cast<T>(result);
215           } else {
216               // None of PyInt_AsUnsigned*() functions check for negative
217               // overflow, so use PyInt_AS_LONG instead and check if number is
218               // negative, issuing the exception appropriately.
219               long result = PyInt_AS_LONG(intermediate);
220               if (PyErr_Occurred())
221                   throw_error_already_set();
222               if (result < 0) {
223                   PyErr_SetString(PyExc_OverflowError, "can't convert negative"
224                                   " value to unsigned");
225                   throw_error_already_set();
226               }
227               return numeric_cast<T>(result);
228           }
229       }
230   };
231 #endif // PY_VERSION_HEX >= 0x03000000
232 
233 // Checking Python's macro instead of Boost's - we don't seem to get
234 // the config right all the time. Furthermore, Python's is defined
235 // when long long is absent but __int64 is present.
236 
237 #ifdef HAVE_LONG_LONG
238   // A SlotPolicy for extracting long long types from Python objects
239 
240   struct long_long_rvalue_from_python_base
241   {
get_slotboost::python::converter::__anonb96b74d40111::long_long_rvalue_from_python_base242       static unaryfunc* get_slot(PyObject* obj)
243       {
244 #if PY_VERSION_HEX >= 0x03000000
245           return PyLong_Check(obj) ? &py_object_identity : 0;
246 #else
247           PyNumberMethods* number_methods = obj->ob_type->tp_as_number;
248           if (number_methods == 0)
249               return 0;
250 
251           // Return the identity conversion slot to avoid creating a
252           // new object. We'll handle that in the extract function
253           if (PyInt_Check(obj))
254               return &number_methods->nb_int;
255           else if (PyLong_Check(obj))
256               return &number_methods->nb_long;
257           else
258               return 0;
259 #endif
260       }
get_pytypeboost::python::converter::__anonb96b74d40111::long_long_rvalue_from_python_base261       static PyTypeObject const* get_pytype() { return &PyLong_Type;}
262   };
263 
264   struct long_long_rvalue_from_python : long_long_rvalue_from_python_base
265   {
extractboost::python::converter::__anonb96b74d40111::long_long_rvalue_from_python266       static BOOST_PYTHON_LONG_LONG extract(PyObject* intermediate)
267       {
268 #if PY_VERSION_HEX < 0x03000000
269           if (PyInt_Check(intermediate))
270           {
271               return PyInt_AS_LONG(intermediate);
272           }
273           else
274 #endif
275           {
276               BOOST_PYTHON_LONG_LONG result = PyLong_AsLongLong(intermediate);
277 
278               if (PyErr_Occurred())
279                   throw_error_already_set();
280 
281               return result;
282           }
283       }
284   };
285 
286   struct unsigned_long_long_rvalue_from_python : long_long_rvalue_from_python_base
287   {
extractboost::python::converter::__anonb96b74d40111::unsigned_long_long_rvalue_from_python288       static unsigned BOOST_PYTHON_LONG_LONG extract(PyObject* intermediate)
289       {
290 #if PY_VERSION_HEX < 0x03000000
291           if (PyInt_Check(intermediate))
292           {
293               return numeric_cast<unsigned BOOST_PYTHON_LONG_LONG>(PyInt_AS_LONG(intermediate));
294           }
295           else
296 #endif
297           {
298               unsigned BOOST_PYTHON_LONG_LONG result = PyLong_AsUnsignedLongLong(intermediate);
299 
300               if (PyErr_Occurred())
301                   throw_error_already_set();
302 
303               return result;
304           }
305       }
306   };
307 #endif
308 
309   // A SlotPolicy for extracting bool from a Python object
310   struct bool_rvalue_from_python
311   {
get_slotboost::python::converter::__anonb96b74d40111::bool_rvalue_from_python312       static unaryfunc* get_slot(PyObject* obj)
313       {
314 #if PY_VERSION_HEX >= 0x03000000
315           return obj == Py_None || PyLong_Check(obj) ? &py_object_identity : 0;
316 #elif PY_VERSION_HEX >= 0x02040000 && defined(BOOST_PYTHON_BOOL_INT_STRICT)
317           return obj == Py_None || PyBool_Check(obj) ? &py_object_identity : 0;
318 #else
319           return obj == Py_None || PyInt_Check(obj) ? &py_object_identity : 0;
320 #endif
321       }
322 
extractboost::python::converter::__anonb96b74d40111::bool_rvalue_from_python323       static bool extract(PyObject* intermediate)
324       {
325           return PyObject_IsTrue(intermediate);
326       }
327 
get_pytypeboost::python::converter::__anonb96b74d40111::bool_rvalue_from_python328       static PyTypeObject const* get_pytype()
329       {
330 #if PY_VERSION_HEX >= 0x02030000
331         return &PyBool_Type;
332 #else
333         return &PyInt_Type;
334 #endif
335       }
336   };
337 
338   // A SlotPolicy for extracting floating types from Python objects.
339   struct float_rvalue_from_python
340   {
get_slotboost::python::converter::__anonb96b74d40111::float_rvalue_from_python341       static unaryfunc* get_slot(PyObject* obj)
342       {
343           PyNumberMethods* number_methods = obj->ob_type->tp_as_number;
344           if (number_methods == 0)
345               return 0;
346 
347           // For integer types, return the tp_int conversion slot to avoid
348           // creating a new object. We'll handle that below
349 #if PY_VERSION_HEX < 0x03000000
350           if (PyInt_Check(obj))
351               return &number_methods->nb_int;
352 #endif
353 
354           return (PyLong_Check(obj) || PyFloat_Check(obj))
355               ? &number_methods->nb_float : 0;
356       }
357 
extractboost::python::converter::__anonb96b74d40111::float_rvalue_from_python358       static double extract(PyObject* intermediate)
359       {
360 #if PY_VERSION_HEX < 0x03000000
361           if (PyInt_Check(intermediate))
362           {
363               return PyInt_AS_LONG(intermediate);
364           }
365           else
366 #endif
367           {
368               return PyFloat_AS_DOUBLE(intermediate);
369           }
370       }
get_pytypeboost::python::converter::__anonb96b74d40111::float_rvalue_from_python371       static PyTypeObject const* get_pytype() { return &PyFloat_Type;}
372   };
373 
374 #if PY_VERSION_HEX >= 0x03000000
375   unaryfunc py_unicode_as_string_unaryfunc = PyUnicode_AsUTF8String;
376 #endif
377 
378   // A SlotPolicy for extracting C++ strings from Python objects.
379   struct string_rvalue_from_python
380   {
381       // If the underlying object is "string-able" this will succeed
get_slotboost::python::converter::__anonb96b74d40111::string_rvalue_from_python382       static unaryfunc* get_slot(PyObject* obj)
383       {
384 #if PY_VERSION_HEX >= 0x03000000
385           return (PyUnicode_Check(obj)) ? &py_unicode_as_string_unaryfunc :
386                   PyBytes_Check(obj) ? &py_object_identity : 0;
387 #else
388           return (PyString_Check(obj)) ? &obj->ob_type->tp_str : 0;
389 
390 #endif
391       };
392 
393       // Remember that this will be used to construct the result object
394 #if PY_VERSION_HEX >= 0x03000000
extractboost::python::converter::__anonb96b74d40111::string_rvalue_from_python395       static std::string extract(PyObject* intermediate)
396       {
397           return std::string(PyBytes_AsString(intermediate),PyBytes_Size(intermediate));
398       }
get_pytypeboost::python::converter::__anonb96b74d40111::string_rvalue_from_python399       static PyTypeObject const* get_pytype() { return &PyUnicode_Type;}
400 #else
extractboost::python::converter::__anonb96b74d40111::string_rvalue_from_python401       static std::string extract(PyObject* intermediate)
402       {
403           return std::string(PyString_AsString(intermediate),PyString_Size(intermediate));
404       }
get_pytypeboost::python::converter::__anonb96b74d40111::string_rvalue_from_python405       static PyTypeObject const* get_pytype() { return &PyString_Type;}
406 #endif
407   };
408 
409 #if defined(Py_USING_UNICODE) && !defined(BOOST_NO_STD_WSTRING)
410   // encode_string_unaryfunc/py_encode_string -- manufacture a unaryfunc
411   // "slot" which encodes a Python string using the default encoding
encode_string_unaryfunc(PyObject * x)412   extern "C" PyObject* encode_string_unaryfunc(PyObject* x)
413   {
414       return PyUnicode_FromEncodedObject( x, 0, 0 );
415   }
416   unaryfunc py_encode_string = encode_string_unaryfunc;
417 
418   // A SlotPolicy for extracting C++ strings from Python objects.
419   struct wstring_rvalue_from_python
420   {
421       // If the underlying object is "string-able" this will succeed
get_slotboost::python::converter::__anonb96b74d40111::wstring_rvalue_from_python422       static unaryfunc* get_slot(PyObject* obj)
423       {
424           return PyUnicode_Check(obj)
425               ? &py_object_identity
426 #if PY_VERSION_HEX >= 0x03000000
427             : PyBytes_Check(obj)
428 #else
429             : PyString_Check(obj)
430 #endif
431               ? &py_encode_string
432             : 0;
433       };
434 
435       // Remember that this will be used to construct the result object
extractboost::python::converter::__anonb96b74d40111::wstring_rvalue_from_python436       static std::wstring extract(PyObject* intermediate)
437       {
438           // On Windows, with Python >= 3.3, PyObject_Length cannot be used to get
439           // the size of the wchar_t string, because it will count the number of
440           // *code points*, but some characters not on the BMP will use two UTF-16
441           // *code units* (surrogate pairs).
442           // This is not a problem on Unix, since wchar_t is 32-bit.
443 #if defined(_WIN32) && PY_VERSION_HEX >= 0x03030000
444           BOOST_STATIC_ASSERT(sizeof(wchar_t) == 2);
445 
446           Py_ssize_t size = 0;
447           wchar_t *buf = PyUnicode_AsWideCharString(intermediate, &size);
448           if (buf == NULL) {
449               boost::python::throw_error_already_set();
450           }
451           std::wstring result(buf, size);
452           PyMem_Free(buf);
453 #else
454           std::wstring result(::PyObject_Length(intermediate), L' ');
455           if (!result.empty())
456           {
457               int err = PyUnicode_AsWideChar(
458 #if PY_VERSION_HEX < 0x03020000
459                   (PyUnicodeObject *)
460 #endif
461                     intermediate
462                 , &result[0]
463                 , result.size());
464 
465               if (err == -1)
466                   throw_error_already_set();
467           }
468 #endif
469           return result;
470       }
get_pytypeboost::python::converter::__anonb96b74d40111::wstring_rvalue_from_python471       static PyTypeObject const* get_pytype() { return &PyUnicode_Type;}
472   };
473 #endif
474 
475   struct complex_rvalue_from_python
476   {
get_slotboost::python::converter::__anonb96b74d40111::complex_rvalue_from_python477       static unaryfunc* get_slot(PyObject* obj)
478       {
479           if (PyComplex_Check(obj))
480               return &py_object_identity;
481           else
482               return float_rvalue_from_python::get_slot(obj);
483       }
484 
extractboost::python::converter::__anonb96b74d40111::complex_rvalue_from_python485       static std::complex<double> extract(PyObject* intermediate)
486       {
487           if (PyComplex_Check(intermediate))
488           {
489               return std::complex<double>(
490                   PyComplex_RealAsDouble(intermediate)
491                   , PyComplex_ImagAsDouble(intermediate));
492           }
493 #if PY_VERSION_HEX < 0x03000000
494           else if (PyInt_Check(intermediate))
495           {
496               return PyInt_AS_LONG(intermediate);
497           }
498 #endif
499           else
500           {
501               return PyFloat_AS_DOUBLE(intermediate);
502           }
503       }
get_pytypeboost::python::converter::__anonb96b74d40111::complex_rvalue_from_python504       static PyTypeObject const* get_pytype() { return &PyComplex_Type;}
505   };
506 }
507 
do_return_to_python(char x)508 BOOST_PYTHON_DECL PyObject* do_return_to_python(char x)
509 {
510 #if PY_VERSION_HEX >= 0x03000000
511     return PyUnicode_FromStringAndSize(&x, 1);
512 #else
513     return PyString_FromStringAndSize(&x, 1);
514 #endif
515 }
516 
do_return_to_python(char const * x)517 BOOST_PYTHON_DECL PyObject* do_return_to_python(char const* x)
518 {
519 #if PY_VERSION_HEX >= 0x03000000
520     return x ? PyUnicode_FromString(x) : boost::python::detail::none();
521 #else
522     return x ? PyString_FromString(x) : boost::python::detail::none();
523 #endif
524 }
525 
do_return_to_python(PyObject * x)526 BOOST_PYTHON_DECL PyObject* do_return_to_python(PyObject* x)
527 {
528     return x ? x : boost::python::detail::none();
529 }
530 
do_arg_to_python(PyObject * x)531 BOOST_PYTHON_DECL PyObject* do_arg_to_python(PyObject* x)
532 {
533     if (x == 0)
534         return boost::python::detail::none();
535 
536     Py_INCREF(x);
537     return x;
538 }
539 
540 #define REGISTER_INT_CONVERTERS(signedness, U)                          \
541         slot_rvalue_from_python<                                        \
542                 signedness U                                            \
543                 ,signedness##_int_rvalue_from_python<signedness U>      \
544          >()
545 
546 #define REGISTER_INT_CONVERTERS2(U)             \
547         REGISTER_INT_CONVERTERS(signed, U);     \
548         REGISTER_INT_CONVERTERS(unsigned, U)
549 
initialize_builtin_converters()550 void initialize_builtin_converters()
551 {
552     // booleans
553     slot_rvalue_from_python<bool,bool_rvalue_from_python>();
554 
555     // integer types
556     REGISTER_INT_CONVERTERS2(char);
557     REGISTER_INT_CONVERTERS2(short);
558     REGISTER_INT_CONVERTERS2(int);
559     REGISTER_INT_CONVERTERS2(long);
560 
561 // using Python's macro instead of Boost's - we don't seem to get the
562 // config right all the time.
563 # ifdef HAVE_LONG_LONG
564     slot_rvalue_from_python<signed BOOST_PYTHON_LONG_LONG,long_long_rvalue_from_python>();
565     slot_rvalue_from_python<unsigned BOOST_PYTHON_LONG_LONG,unsigned_long_long_rvalue_from_python>();
566 # endif
567 
568     // floating types
569     slot_rvalue_from_python<float,float_rvalue_from_python>();
570     slot_rvalue_from_python<double,float_rvalue_from_python>();
571     slot_rvalue_from_python<long double,float_rvalue_from_python>();
572 
573     slot_rvalue_from_python<std::complex<float>,complex_rvalue_from_python>();
574     slot_rvalue_from_python<std::complex<double>,complex_rvalue_from_python>();
575     slot_rvalue_from_python<std::complex<long double>,complex_rvalue_from_python>();
576 
577     // Add an lvalue converter for char which gets us char const*
578 #if PY_VERSION_HEX < 0x03000000
579     registry::insert(convert_to_cstring,type_id<char>(),&converter::wrap_pytype<&PyString_Type>::get_pytype);
580 #else
581     registry::insert(convert_to_cstring,type_id<char>(),&converter::wrap_pytype<&PyUnicode_Type>::get_pytype);
582 #endif
583 
584     // Register by-value converters to std::string, std::wstring
585 #if defined(Py_USING_UNICODE) && !defined(BOOST_NO_STD_WSTRING)
586     slot_rvalue_from_python<std::wstring, wstring_rvalue_from_python>();
587 # endif
588     slot_rvalue_from_python<std::string, string_rvalue_from_python>();
589 
590 }
591 
592 }}} // namespace boost::python::converter
593