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/converter/from_python.hpp> 7 #include <boost/python/converter/registrations.hpp> 8 #include <boost/python/converter/rvalue_from_python_data.hpp> 9 10 #include <boost/python/object/find_instance.hpp> 11 12 #include <boost/python/handle.hpp> 13 #include <boost/python/detail/raw_pyobject.hpp> 14 #include <boost/python/cast.hpp> 15 16 #include <vector> 17 #include <algorithm> 18 19 namespace boost { namespace python { namespace converter { 20 21 // rvalue_from_python_stage1 -- do the first stage of a conversion 22 // from a Python object to a C++ rvalue. 23 // 24 // source - the Python object to be converted 25 // converters - the registry entry for the target type T 26 // 27 // Postcondition: where x is the result, one of: 28 // 29 // 1. x.convertible == 0, indicating failure 30 // 31 // 2. x.construct == 0, x.convertible is the address of an object of 32 // type T. Indicates a successful lvalue conversion 33 // 34 // 3. where y is of type rvalue_from_python_data<T>, 35 // x.construct(source, y) constructs an object of type T 36 // in y.storage.bytes and then sets y.convertible == y.storage.bytes, 37 // or else throws an exception and has no effect. rvalue_from_python_stage1(PyObject * source,registration const & converters)38 BOOST_PYTHON_DECL rvalue_from_python_stage1_data rvalue_from_python_stage1( 39 PyObject* source 40 , registration const& converters) 41 { 42 rvalue_from_python_stage1_data data; 43 44 // First check to see if it's embedded in an extension class 45 // instance, as a special case. 46 data.convertible = objects::find_instance_impl(source, converters.target_type, converters.is_shared_ptr); 47 data.construct = 0; 48 if (!data.convertible) 49 { 50 for (rvalue_from_python_chain const* chain = converters.rvalue_chain; 51 chain != 0; 52 chain = chain->next) 53 { 54 void* r = chain->convertible(source); 55 if (r != 0) 56 { 57 data.convertible = r; 58 data.construct = chain->construct; 59 break; 60 } 61 } 62 } 63 return data; 64 } 65 66 // rvalue_result_from_python -- return the address of a C++ object which 67 // can be used as the result of calling a Python function. 68 // 69 // src - the Python object to be converted 70 // 71 // data - a reference to the base part of a 72 // rvalue_from_python_data<T> object, where T is the 73 // target type of the conversion. 74 // 75 // Requires: data.convertible == ®istered<T>::converters 76 // rvalue_result_from_python(PyObject * src,rvalue_from_python_stage1_data & data)77 BOOST_PYTHON_DECL void* rvalue_result_from_python( 78 PyObject* src, rvalue_from_python_stage1_data& data) 79 { 80 // Retrieve the registration 81 // Cast in two steps for less-capable compilers 82 void const* converters_ = data.convertible; 83 registration const& converters = *static_cast<registration const*>(converters_); 84 85 // Look for an eligible converter 86 data = rvalue_from_python_stage1(src, converters); 87 return rvalue_from_python_stage2(src, data, converters); 88 } 89 rvalue_from_python_stage2(PyObject * source,rvalue_from_python_stage1_data & data,registration const & converters)90 BOOST_PYTHON_DECL void* rvalue_from_python_stage2( 91 PyObject* source, rvalue_from_python_stage1_data& data, registration const& converters) 92 { 93 if (!data.convertible) 94 { 95 handle<> msg( 96 #if PY_VERSION_HEX >= 0x03000000 97 ::PyUnicode_FromFormat 98 #else 99 ::PyString_FromFormat 100 #endif 101 ( 102 "No registered converter was able to produce a C++ rvalue of type %s from this Python object of type %s" 103 , converters.target_type.name() 104 , source->ob_type->tp_name 105 )); 106 107 PyErr_SetObject(PyExc_TypeError, msg.get()); 108 throw_error_already_set(); 109 } 110 111 // If a construct function was registered (i.e. we found an 112 // rvalue conversion), call it now. 113 if (data.construct != 0) 114 data.construct(source, &data); 115 116 // Return the address of the resulting C++ object 117 return data.convertible; 118 } 119 get_lvalue_from_python(PyObject * source,registration const & converters)120 BOOST_PYTHON_DECL void* get_lvalue_from_python( 121 PyObject* source 122 , registration const& converters) 123 { 124 // Check to see if it's embedded in a class instance 125 void* x = objects::find_instance_impl(source, converters.target_type); 126 if (x) 127 return x; 128 129 lvalue_from_python_chain const* chain = converters.lvalue_chain; 130 for (;chain != 0; chain = chain->next) 131 { 132 void* r = chain->convert(source); 133 if (r != 0) 134 return r; 135 } 136 return 0; 137 } 138 139 namespace 140 { 141 // Prevent looping in implicit conversions. This could/should be 142 // much more efficient, but will work for now. 143 typedef std::vector<rvalue_from_python_chain const*> visited_t; 144 static visited_t visited; 145 visit(rvalue_from_python_chain const * chain)146 inline bool visit(rvalue_from_python_chain const* chain) 147 { 148 visited_t::iterator const p = std::lower_bound(visited.begin(), visited.end(), chain); 149 if (p != visited.end() && *p == chain) 150 return false; 151 visited.insert(p, chain); 152 return true; 153 } 154 155 // RAII class for managing global visited marks. 156 struct unvisit 157 { unvisitboost::python::converter::__anon96dfd1270111::unvisit158 unvisit(rvalue_from_python_chain const* chain) 159 : chain(chain) {} 160 ~unvisitboost::python::converter::__anon96dfd1270111::unvisit161 ~unvisit() 162 { 163 visited_t::iterator const p = std::lower_bound(visited.begin(), visited.end(), chain); 164 assert(p != visited.end()); 165 visited.erase(p); 166 } 167 private: 168 rvalue_from_python_chain const* chain; 169 }; 170 } 171 172 implicit_rvalue_convertible_from_python(PyObject * source,registration const & converters)173 BOOST_PYTHON_DECL bool implicit_rvalue_convertible_from_python( 174 PyObject* source 175 , registration const& converters) 176 { 177 if (objects::find_instance_impl(source, converters.target_type)) 178 return true; 179 180 rvalue_from_python_chain const* chain = converters.rvalue_chain; 181 182 if (!visit(chain)) 183 return false; 184 185 unvisit protect(chain); 186 187 for (;chain != 0; chain = chain->next) 188 { 189 if (chain->convertible(source)) 190 return true; 191 } 192 193 return false; 194 } 195 196 namespace 197 { throw_no_lvalue_from_python(PyObject * source,registration const & converters,char const * ref_type)198 void throw_no_lvalue_from_python(PyObject* source, registration const& converters, char const* ref_type) 199 { 200 handle<> msg( 201 #if PY_VERSION_HEX >= 0x03000000 202 ::PyUnicode_FromFormat 203 #else 204 ::PyString_FromFormat 205 #endif 206 ( 207 "No registered converter was able to extract a C++ %s to type %s" 208 " from this Python object of type %s" 209 , ref_type 210 , converters.target_type.name() 211 , source->ob_type->tp_name 212 )); 213 214 PyErr_SetObject(PyExc_TypeError, msg.get()); 215 216 throw_error_already_set(); 217 } 218 lvalue_result_from_python(PyObject * source,registration const & converters,char const * ref_type)219 void* lvalue_result_from_python( 220 PyObject* source 221 , registration const& converters 222 , char const* ref_type) 223 { 224 handle<> holder(source); 225 if (source->ob_refcnt <= 1) 226 { 227 handle<> msg( 228 #if PY_VERSION_HEX >= 0x3000000 229 ::PyUnicode_FromFormat 230 #else 231 ::PyString_FromFormat 232 #endif 233 ( 234 "Attempt to return dangling %s to object of type: %s" 235 , ref_type 236 , converters.target_type.name())); 237 238 PyErr_SetObject(PyExc_ReferenceError, msg.get()); 239 240 throw_error_already_set(); 241 } 242 243 void* result = get_lvalue_from_python(source, converters); 244 if (!result) 245 (throw_no_lvalue_from_python)(source, converters, ref_type); 246 return result; 247 } 248 249 } 250 throw_no_pointer_from_python(PyObject * source,registration const & converters)251 BOOST_PYTHON_DECL void throw_no_pointer_from_python(PyObject* source, registration const& converters) 252 { 253 (throw_no_lvalue_from_python)(source, converters, "pointer"); 254 } 255 throw_no_reference_from_python(PyObject * source,registration const & converters)256 BOOST_PYTHON_DECL void throw_no_reference_from_python(PyObject* source, registration const& converters) 257 { 258 (throw_no_lvalue_from_python)(source, converters, "reference"); 259 } 260 reference_result_from_python(PyObject * source,registration const & converters)261 BOOST_PYTHON_DECL void* reference_result_from_python( 262 PyObject* source 263 , registration const& converters) 264 { 265 return (lvalue_result_from_python)(source, converters, "reference"); 266 } 267 pointer_result_from_python(PyObject * source,registration const & converters)268 BOOST_PYTHON_DECL void* pointer_result_from_python( 269 PyObject* source 270 , registration const& converters) 271 { 272 if (source == Py_None) 273 { 274 Py_DECREF(source); 275 return 0; 276 } 277 return (lvalue_result_from_python)(source, converters, "pointer"); 278 } 279 void_result_from_python(PyObject * o)280 BOOST_PYTHON_DECL void void_result_from_python(PyObject* o) 281 { 282 Py_DECREF(expect_non_null(o)); 283 } 284 285 } // namespace boost::python::converter 286 287 BOOST_PYTHON_DECL PyObject* pytype_check(PyTypeObject * type_,PyObject * source)288 pytype_check(PyTypeObject* type_, PyObject* source) 289 { 290 if (!PyObject_IsInstance(source, python::upcast<PyObject>(type_))) 291 { 292 ::PyErr_Format( 293 PyExc_TypeError 294 , "Expecting an object of type %s; got an object of type %s instead" 295 , type_->tp_name 296 , source->ob_type->tp_name 297 ); 298 throw_error_already_set(); 299 } 300 return source; 301 } 302 303 }} // namespace boost::python 304