| 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 |  | 
|---|
| 24 | namespace boost { namespace python { namespace converter { | 
|---|
| 25 |  | 
|---|
| 26 | shared_ptr_deleter::shared_ptr_deleter(handle<> owner) | 
|---|
| 27 |     : owner(owner) | 
|---|
| 28 | {} | 
|---|
| 29 |  | 
|---|
| 30 | shared_ptr_deleter::~shared_ptr_deleter() {} | 
|---|
| 31 |  | 
|---|
| 32 | void shared_ptr_deleter::operator()(void const*) | 
|---|
| 33 | { | 
|---|
| 34 |     owner.reset(); | 
|---|
| 35 | } | 
|---|
| 36 |  | 
|---|
| 37 | namespace | 
|---|
| 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 |  | 
|---|
| 352 | BOOST_PYTHON_DECL PyObject* do_return_to_python(char x) | 
|---|
| 353 | { | 
|---|
| 354 |     return PyString_FromStringAndSize(&x, 1); | 
|---|
| 355 | } | 
|---|
| 356 |    | 
|---|
| 357 | BOOST_PYTHON_DECL PyObject* do_return_to_python(char const* x) | 
|---|
| 358 | { | 
|---|
| 359 |     return x ? PyString_FromString(x) : boost::python::detail::none(); | 
|---|
| 360 | } | 
|---|
| 361 |    | 
|---|
| 362 | BOOST_PYTHON_DECL PyObject* do_return_to_python(PyObject* x) | 
|---|
| 363 | { | 
|---|
| 364 |     return x ? x : boost::python::detail::none(); | 
|---|
| 365 | } | 
|---|
| 366 |    | 
|---|
| 367 | BOOST_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 |  | 
|---|
| 386 | void 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 | 
|---|