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 #ifndef FROM_PYTHON_AUX_DATA_DWA2002128_HPP 6 # define FROM_PYTHON_AUX_DATA_DWA2002128_HPP 7 8 # include <boost/python/converter/constructor_function.hpp> 9 # include <boost/python/detail/referent_storage.hpp> 10 # include <boost/python/detail/destroy.hpp> 11 # include <boost/python/detail/type_traits.hpp> 12 # include <boost/static_assert.hpp> 13 # include <cstddef> 14 15 // Data management for potential rvalue conversions from Python to C++ 16 // types. When a client requests a conversion to T* or T&, we 17 // generally require that an object of type T exists in the source 18 // Python object, and the code here does not apply**. This implements 19 // conversions which may create new temporaries of type T. The classic 20 // example is a conversion which converts a Python tuple to a 21 // std::vector. Since no std::vector lvalue exists in the Python 22 // object -- it must be created "on-the-fly" by the converter, and 23 // which must manage the lifetime of the created object. 24 // 25 // Note that the client is not precluded from using a registered 26 // lvalue conversion to T in this case. In other words, we will 27 // happily accept a Python object which /does/ contain a std::vector 28 // lvalue, provided an appropriate converter is registered. So, while 29 // this is an rvalue conversion from the client's point-of-view, the 30 // converter registry may serve up lvalue or rvalue conversions for 31 // the target type. 32 // 33 // ** C++ argument from_python conversions to T const& are an 34 // exception to the rule for references: since in C++, const 35 // references can bind to temporary rvalues, we allow rvalue 36 // converters to be chosen when the target type is T const& for some 37 // T. 38 namespace boost { namespace python { namespace converter { 39 40 // Conversions begin by filling in and returning a copy of this 41 // structure. The process looks up a converter in the rvalue converter 42 // registry for the target type. It calls the convertible() function 43 // of each registered converter, passing the source PyObject* as an 44 // argument, until a non-null result is returned. This result goes in 45 // the convertible field, and the converter's construct() function is 46 // stored in the construct field. 47 // 48 // If no appropriate converter is found, conversion fails and the 49 // convertible field is null. When used in argument conversion for 50 // wrapped C++ functions, it causes overload resolution to reject the 51 // current function but not to fail completely. If an exception is 52 // thrown, overload resolution stops and the exception propagates back 53 // through the caller. 54 // 55 // If an lvalue converter is matched, its convertible() function is 56 // expected to return a pointer to the stored T object; its 57 // construct() function will be NULL. The convertible() function of 58 // rvalue converters may return any non-singular pointer; the actual 59 // target object will only be available once the converter's 60 // construct() function is called. 61 struct rvalue_from_python_stage1_data 62 { 63 void* convertible; 64 constructor_function construct; 65 }; 66 67 // Augments rvalue_from_python_stage1_data by adding storage for 68 // constructing an object of remove_reference<T>::type. The 69 // construct() function of rvalue converters (stored in m_construct 70 // above) will cast the rvalue_from_python_stage1_data to an 71 // appropriate instantiation of this template in order to access that 72 // storage. 73 template <class T> 74 struct rvalue_from_python_storage 75 { 76 rvalue_from_python_stage1_data stage1; 77 78 // Storage for the result, in case an rvalue must be constructed 79 typename python::detail::referent_storage< 80 typename boost::python::detail::add_lvalue_reference<T>::type 81 >::type storage; 82 }; 83 84 // Augments rvalue_from_python_storage<T> with a destructor. If 85 // stage1.convertible == storage.bytes, it indicates that an object of 86 // remove_reference<T>::type has been constructed in storage and 87 // should will be destroyed in ~rvalue_from_python_data(). It is 88 // crucial that successful rvalue conversions establish this equality 89 // and that unsuccessful ones do not. 90 template <class T> 91 struct rvalue_from_python_data : rvalue_from_python_storage<T> 92 { 93 # if (!defined(__MWERKS__) || __MWERKS__ >= 0x3000) \ 94 && (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 245) \ 95 && (!defined(__DECCXX_VER) || __DECCXX_VER > 60590014) \ 96 && !defined(BOOST_PYTHON_SYNOPSIS) /* Synopsis' OpenCXX has trouble parsing this */ 97 // This must always be a POD struct with m_data its first member. 98 BOOST_STATIC_ASSERT(BOOST_PYTHON_OFFSETOF(rvalue_from_python_storage<T>,stage1) == 0); 99 # endif 100 101 // The usual constructor 102 rvalue_from_python_data(rvalue_from_python_stage1_data const&); 103 104 // This constructor just sets m_convertible -- used by 105 // implicitly_convertible<> to perform the final step of the 106 // conversion, where the construct() function is already known. 107 rvalue_from_python_data(void* convertible); 108 109 // Destroys any object constructed in the storage. 110 ~rvalue_from_python_data(); 111 private: 112 typedef typename boost::python::detail::add_lvalue_reference< 113 typename boost::python::detail::add_cv<T>::type>::type ref_type; 114 }; 115 116 // 117 // Implementataions 118 // 119 template <class T> rvalue_from_python_data(rvalue_from_python_stage1_data const & _stage1)120 inline rvalue_from_python_data<T>::rvalue_from_python_data(rvalue_from_python_stage1_data const& _stage1) 121 { 122 this->stage1 = _stage1; 123 } 124 125 template <class T> rvalue_from_python_data(void * convertible)126 inline rvalue_from_python_data<T>::rvalue_from_python_data(void* convertible) 127 { 128 this->stage1.convertible = convertible; 129 } 130 131 template <class T> ~rvalue_from_python_data()132 inline rvalue_from_python_data<T>::~rvalue_from_python_data() 133 { 134 if (this->stage1.convertible == this->storage.bytes) 135 python::detail::destroy_referent<ref_type>(this->storage.bytes); 136 } 137 138 }}} // namespace boost::python::converter 139 140 #endif // FROM_PYTHON_AUX_DATA_DWA2002128_HPP 141