Chris@16: // Copyright David Abrahams 2002. Chris@16: // Distributed under the Boost Software License, Version 1.0. (See Chris@16: // accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: #ifndef FROM_PYTHON_AUX_DATA_DWA2002128_HPP Chris@16: # define FROM_PYTHON_AUX_DATA_DWA2002128_HPP Chris@16: Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: Chris@16: // Data management for potential rvalue conversions from Python to C++ Chris@16: // types. When a client requests a conversion to T* or T&, we Chris@16: // generally require that an object of type T exists in the source Chris@16: // Python object, and the code here does not apply**. This implements Chris@16: // conversions which may create new temporaries of type T. The classic Chris@16: // example is a conversion which converts a Python tuple to a Chris@16: // std::vector. Since no std::vector lvalue exists in the Python Chris@16: // object -- it must be created "on-the-fly" by the converter, and Chris@16: // which must manage the lifetime of the created object. Chris@16: // Chris@16: // Note that the client is not precluded from using a registered Chris@16: // lvalue conversion to T in this case. In other words, we will Chris@16: // happily accept a Python object which /does/ contain a std::vector Chris@16: // lvalue, provided an appropriate converter is registered. So, while Chris@16: // this is an rvalue conversion from the client's point-of-view, the Chris@16: // converter registry may serve up lvalue or rvalue conversions for Chris@16: // the target type. Chris@16: // Chris@16: // ** C++ argument from_python conversions to T const& are an Chris@16: // exception to the rule for references: since in C++, const Chris@16: // references can bind to temporary rvalues, we allow rvalue Chris@16: // converters to be chosen when the target type is T const& for some Chris@16: // T. Chris@16: namespace boost { namespace python { namespace converter { Chris@16: Chris@16: // Conversions begin by filling in and returning a copy of this Chris@16: // structure. The process looks up a converter in the rvalue converter Chris@16: // registry for the target type. It calls the convertible() function Chris@16: // of each registered converter, passing the source PyObject* as an Chris@16: // argument, until a non-null result is returned. This result goes in Chris@16: // the convertible field, and the converter's construct() function is Chris@16: // stored in the construct field. Chris@16: // Chris@16: // If no appropriate converter is found, conversion fails and the Chris@16: // convertible field is null. When used in argument conversion for Chris@16: // wrapped C++ functions, it causes overload resolution to reject the Chris@16: // current function but not to fail completely. If an exception is Chris@16: // thrown, overload resolution stops and the exception propagates back Chris@16: // through the caller. Chris@16: // Chris@16: // If an lvalue converter is matched, its convertible() function is Chris@16: // expected to return a pointer to the stored T object; its Chris@16: // construct() function will be NULL. The convertible() function of Chris@16: // rvalue converters may return any non-singular pointer; the actual Chris@16: // target object will only be available once the converter's Chris@16: // construct() function is called. Chris@16: struct rvalue_from_python_stage1_data Chris@16: { Chris@16: void* convertible; Chris@16: constructor_function construct; Chris@16: }; Chris@16: Chris@16: // Augments rvalue_from_python_stage1_data by adding storage for Chris@16: // constructing an object of remove_reference::type. The Chris@16: // construct() function of rvalue converters (stored in m_construct Chris@16: // above) will cast the rvalue_from_python_stage1_data to an Chris@16: // appropriate instantiation of this template in order to access that Chris@16: // storage. Chris@16: template Chris@16: struct rvalue_from_python_storage Chris@16: { Chris@16: rvalue_from_python_stage1_data stage1; Chris@16: Chris@16: // Storage for the result, in case an rvalue must be constructed Chris@16: typename python::detail::referent_storage< Chris@16: typename add_reference::type Chris@16: >::type storage; Chris@16: }; Chris@16: Chris@16: // Augments rvalue_from_python_storage with a destructor. If Chris@16: // stage1.convertible == storage.bytes, it indicates that an object of Chris@16: // remove_reference::type has been constructed in storage and Chris@16: // should will be destroyed in ~rvalue_from_python_data(). It is Chris@16: // crucial that successful rvalue conversions establish this equality Chris@16: // and that unsuccessful ones do not. Chris@16: template Chris@16: struct rvalue_from_python_data : rvalue_from_python_storage Chris@16: { Chris@16: # if (!defined(__MWERKS__) || __MWERKS__ >= 0x3000) \ Chris@16: && (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 245) \ Chris@16: && (!defined(__DECCXX_VER) || __DECCXX_VER > 60590014) \ Chris@16: && !defined(BOOST_PYTHON_SYNOPSIS) /* Synopsis' OpenCXX has trouble parsing this */ Chris@16: // This must always be a POD struct with m_data its first member. Chris@16: BOOST_STATIC_ASSERT(BOOST_PYTHON_OFFSETOF(rvalue_from_python_storage,stage1) == 0); Chris@16: # endif Chris@16: Chris@16: // The usual constructor Chris@16: rvalue_from_python_data(rvalue_from_python_stage1_data const&); Chris@16: Chris@16: // This constructor just sets m_convertible -- used by Chris@16: // implicitly_convertible<> to perform the final step of the Chris@16: // conversion, where the construct() function is already known. Chris@16: rvalue_from_python_data(void* convertible); Chris@16: Chris@16: // Destroys any object constructed in the storage. Chris@16: ~rvalue_from_python_data(); Chris@16: private: Chris@16: typedef typename add_reference::type>::type ref_type; Chris@16: }; Chris@16: Chris@16: // Chris@16: // Implementataions Chris@16: // Chris@16: template Chris@16: inline rvalue_from_python_data::rvalue_from_python_data(rvalue_from_python_stage1_data const& _stage1) Chris@16: { Chris@16: this->stage1 = _stage1; Chris@16: } Chris@16: Chris@16: template Chris@16: inline rvalue_from_python_data::rvalue_from_python_data(void* convertible) Chris@16: { Chris@16: this->stage1.convertible = convertible; Chris@16: } Chris@16: Chris@16: template Chris@16: inline rvalue_from_python_data::~rvalue_from_python_data() Chris@16: { Chris@16: if (this->stage1.convertible == this->storage.bytes) Chris@16: python::detail::destroy_referent(this->storage.bytes); Chris@16: } Chris@16: Chris@16: }}} // namespace boost::python::converter Chris@16: Chris@16: #endif // FROM_PYTHON_AUX_DATA_DWA2002128_HPP