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