📄 from_python.cpp
字号:
// Copyright David Abrahams 2002.// Distributed under the Boost Software License, Version 1.0. (See// accompanying file LICENSE_1_0.txt or copy at// http://www.boost.org/LICENSE_1_0.txt)#include <boost/python/converter/from_python.hpp>#include <boost/python/converter/registrations.hpp>#include <boost/python/converter/rvalue_from_python_data.hpp>#include <boost/python/object/find_instance.hpp>#include <boost/python/handle.hpp>#include <boost/python/detail/raw_pyobject.hpp>#include <boost/python/cast.hpp>#include <vector>#include <algorithm>namespace boost { namespace python { namespace converter { // rvalue_from_python_stage1 -- do the first stage of a conversion// from a Python object to a C++ rvalue.//// source - the Python object to be converted// converters - the registry entry for the target type T//// Postcondition: where x is the result, one of://// 1. x.convertible == 0, indicating failure//// 2. x.construct == 0, x.convertible is the address of an object of// type T. Indicates a successful lvalue conversion//// 3. where y is of type rvalue_from_python_data<T>,// x.construct(source, y) constructs an object of type T// in y.storage.bytes and then sets y.convertible == y.storage.bytes,// or else throws an exception and has no effect.BOOST_PYTHON_DECL rvalue_from_python_stage1_data rvalue_from_python_stage1( PyObject* source , registration const& converters){ rvalue_from_python_stage1_data data; // First check to see if it's embedded in an extension class // instance, as a special case. data.convertible = objects::find_instance_impl(source, converters.target_type, converters.is_shared_ptr); if (data.convertible) { data.construct = 0; } else { for (rvalue_from_python_chain const* chain = converters.rvalue_chain; chain != 0; chain = chain->next) { void* r = chain->convertible(source); if (r != 0) { data.convertible = r; data.construct = chain->construct; break; } } } return data;}// rvalue_result_from_python -- return the address of a C++ object which// can be used as the result of calling a Python function.//// src - the Python object to be converted//// data - a reference to the base part of a// rvalue_from_python_data<T> object, where T is the// target type of the conversion.//// Requires: data.convertible == ®istered<T>::converters//BOOST_PYTHON_DECL void* rvalue_result_from_python( PyObject* src, rvalue_from_python_stage1_data& data){ // Retrieve the registration // Cast in two steps for less-capable compilers void const* converters_ = data.convertible; registration const& converters = *static_cast<registration const*>(converters_); // Look for an eligible converter data = rvalue_from_python_stage1(src, converters); return rvalue_from_python_stage2(src, data, converters);}BOOST_PYTHON_DECL void* rvalue_from_python_stage2( PyObject* source, rvalue_from_python_stage1_data& data, registration const& converters){ if (!data.convertible) { handle<> msg( ::PyString_FromFormat( "No registered converter was able to produce a C++ rvalue of type %s from this Python object of type %s" , converters.target_type.name() , source->ob_type->tp_name )); PyErr_SetObject(PyExc_TypeError, msg.get()); throw_error_already_set(); } // If a construct function was registered (i.e. we found an // rvalue conversion), call it now. if (data.construct != 0) data.construct(source, &data); // Return the address of the resulting C++ object return data.convertible;}BOOST_PYTHON_DECL void* get_lvalue_from_python( PyObject* source , registration const& converters){ // Check to see if it's embedded in a class instance void* x = objects::find_instance_impl(source, converters.target_type); if (x) return x; lvalue_from_python_chain const* chain = converters.lvalue_chain; for (;chain != 0; chain = chain->next) { void* r = chain->convert(source); if (r != 0) return r; } return 0;}namespace{ // Prevent looping in implicit conversions. This could/should be // much more efficient, but will work for now. typedef std::vector<rvalue_from_python_chain const*> visited_t; static visited_t visited; inline bool visit(rvalue_from_python_chain const* chain) { visited_t::iterator const p = std::lower_bound(visited.begin(), visited.end(), chain); if (p != visited.end() && *p == chain) return false; visited.insert(p, chain); return true; } // RAII class for managing global visited marks. struct unvisit { unvisit(rvalue_from_python_chain const* chain) : chain(chain) {} ~unvisit() { visited_t::iterator const p = std::lower_bound(visited.begin(), visited.end(), chain); assert(p != visited.end()); visited.erase(p); } private: rvalue_from_python_chain const* chain; };}BOOST_PYTHON_DECL bool implicit_rvalue_convertible_from_python( PyObject* source , registration const& converters){ if (objects::find_instance_impl(source, converters.target_type)) return true; rvalue_from_python_chain const* chain = converters.rvalue_chain; if (!visit(chain)) return false; unvisit protect(chain); for (;chain != 0; chain = chain->next) { if (chain->convertible(source)) return true; } return false;}namespace{ void throw_no_lvalue_from_python(PyObject* source, registration const& converters, char const* ref_type) { handle<> msg( ::PyString_FromFormat( "No registered converter was able to extract a C++ %s to type %s" " from this Python object of type %s" , ref_type , converters.target_type.name() , source->ob_type->tp_name )); PyErr_SetObject(PyExc_TypeError, msg.get()); throw_error_already_set(); } void* lvalue_result_from_python( PyObject* source , registration const& converters , char const* ref_type) { handle<> holder(source); if (source->ob_refcnt <= 1) { handle<> msg( ::PyString_FromFormat( "Attempt to return dangling %s to object of type: %s" , ref_type , converters.target_type.name())); PyErr_SetObject(PyExc_ReferenceError, msg.get()); throw_error_already_set(); } void* result = get_lvalue_from_python(source, converters); if (!result) (throw_no_lvalue_from_python)(source, converters, ref_type); return result; } }BOOST_PYTHON_DECL void throw_no_pointer_from_python(PyObject* source, registration const& converters){ (throw_no_lvalue_from_python)(source, converters, "pointer");}BOOST_PYTHON_DECL void throw_no_reference_from_python(PyObject* source, registration const& converters){ (throw_no_lvalue_from_python)(source, converters, "reference");}BOOST_PYTHON_DECL void* reference_result_from_python( PyObject* source , registration const& converters){ return (lvalue_result_from_python)(source, converters, "reference");} BOOST_PYTHON_DECL void* pointer_result_from_python( PyObject* source , registration const& converters){ if (source == Py_None) { Py_DECREF(source); return 0; } return (lvalue_result_from_python)(source, converters, "pointer");} BOOST_PYTHON_DECL void void_result_from_python(PyObject* o){ Py_DECREF(expect_non_null(o));}} // namespace boost::python::converterBOOST_PYTHON_DECL PyObject*pytype_check(PyTypeObject* type_, PyObject* source){ if (!PyObject_IsInstance(source, python::upcast<PyObject>(type_))) { ::PyErr_Format( PyExc_TypeError , "Expecting an object of type %s; got an object of type %s instead" , type_->tp_name , source->ob_type->tp_name ); throw_error_already_set(); } return source;}}} // namespace boost::python
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -