diff --git a/Jamfile b/Jamfile index aa804505..79dfd9e5 100644 --- a/Jamfile +++ b/Jamfile @@ -4,14 +4,18 @@ subproject libs/python ; SEARCH on python.jam = $(BOOST_BUILD_PATH) ; include python.jam ; -PYTHON_PROPERTIES - += <*>"-inline deferred" - <*>$(BOOST_ROOT)/boost/compatibility/cpp_c_headers - BOOST_PYTHON_DYNAMIC_LIB - BOOST_PYTHON_V2 - ; { + local BOOST_PYTHON_V2_PROPERTIES + = $(PYTHON_PROPERTIES) + <*>"-inline deferred" + <*>$(BOOST_ROOT)/boost/compatibility/cpp_c_headers + BOOST_PYTHON_DYNAMIC_LIB + BOOST_PYTHON_V2 + ; + + local PYTHON_PROPERTIES = $(BOOST_PYTHON_V2_PROPERTIES) ; + dll bpl : src/converter/from_python.cpp @@ -26,7 +30,7 @@ PYTHON_PROPERTIES src/objects.cpp src/converter/builtin_converters.cpp : - $(PYTHON_PROPERTIES) + $(BOOST_PYTHON_V2_PROPERTIES) BOOST_PYTHON_SOURCE ; @@ -67,4 +71,20 @@ PYTHON_PROPERTIES : : debug-python ; + } + +unit-test indirect_traits_test + : test/indirect_traits_test.cpp : $(BOOST_ROOT) ; +unit-test destroy_test + : test/destroy_test.cpp : $(BOOST_ROOT) ; +unit-test pointer_type_id_test + : test/pointer_type_id_test.cpp : $(BOOST_ROOT) ; + +unit-test select_from_python_test + : test/select_from_python_test.cpp + src/converter/type_id.cpp + src/converter/registry.cpp # MWerks needs this for some reason + : $(PYTHON_PROPERTIES) + ; + diff --git a/doc/v2/module.html b/doc/v2/module.html index 847ff017..3775e4d1 100644 --- a/doc/v2/module.html +++ b/doc/v2/module.html @@ -157,7 +157,7 @@ module& setattr(const char* name, ref const& r);
Effects: Adds the given Python object to the module. If the object is a product of make_function(), the - usual overloading procedure applies. + usual overloading procedure applies. In the first two forms, ownership of a reference to obj is transferred from caller to callee, even if an exception is thrown. diff --git a/include/boost/python/converter/body.hpp b/include/boost/python/converter/body.hpp deleted file mode 100644 index d9170839..00000000 --- a/include/boost/python/converter/body.hpp +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright David Abrahams 2001. Permission to copy, use, -// modify, sell and distribute this software is granted provided this -// copyright notice appears in all copies. This software is provided -// "as is" without express or implied warranty, and with no claim as -// to its suitability for any purpose. -#ifndef BODY_DWA2001127_HPP -# define BODY_DWA2001127_HPP -# include -# include - -namespace boost { namespace python { namespace converter { - -namespace registry -{ - class entry; -} - -struct BOOST_PYTHON_DECL body -{ - public: - body(type_id_t key); - virtual ~body() {} - - type_id_t key() const; - - protected: - // true iff the registry is still alive - bool can_unregister() const; - - private: - // called when the registry is destroyed, to prevent it from being - // unregistered. - void do_not_unregister(); - friend class registry::entry; - - private: - type_id_t m_key; - bool m_can_unregister; -}; - -// -// implementations -// -inline body::body(type_id_t key) - : m_key(key) - , m_can_unregister(true) -{ -} - -inline type_id_t body::key() const -{ - return m_key; -} - -inline bool body::can_unregister() const -{ - return m_can_unregister; -} - -}}} // namespace boost::python::converter - -#endif // BODY_DWA2001127_HPP diff --git a/include/boost/python/converter/class.hpp b/include/boost/python/converter/class.hpp deleted file mode 100644 index 67de6fad..00000000 --- a/include/boost/python/converter/class.hpp +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright David Abrahams 2001. Permission to copy, use, -// modify, sell and distribute this software is granted provided this -// copyright notice appears in all copies. This software is provided -// "as is" without express or implied warranty, and with no claim as -// to its suitability for any purpose. -#ifndef CLASS_DWA20011215_HPP -# define CLASS_DWA20011215_HPP - -# include -# include - -namespace boost { namespace python { namespace converter { - -template -struct class_from_python_converter -{ - class_from_python_converter(); - - static void* convertible(PyObject*); - static T& convert_ref(PyObject*, from_python_data&); - static T const& convert_cref(PyObject*, from_python_data&); - static T* convert_ptr(PyObject*, from_python_data&); - static T const* convert_cptr(PyObject*, from_python_data&); - - from_python_converter to_ref; - from_python_converter to_cref; - from_python_converter to_ptr; - from_python_converter to_cptr; -}; - -// -// implementations -// -template -class_from_python_converter::class_from_python_converter() - : to_ref(convertible, convert_ref) - , to_cref(convertible, convert_cref) - , to_ptr(convertible, convert_ptr) - , to_cptr(convertible, convert_cptr) -{} - -template -T& class_from_python_converter::convert_ref(PyObject*, from_python_data& x) -{ - return *static_cast(x.stage1); -} - -template -T const& class_from_python_converter::convert_cref(PyObject*, from_python_data& x) -{ - return *static_cast(x.stage1); -} - - -template -T* class_from_python_converter::convert_ptr(PyObject*, from_python_data& x) -{ - return static_cast(x.stage1); -} - -template -T const* class_from_python_converter::convert_cptr(PyObject*, from_python_data& x) -{ - return static_cast(x.stage1); -} - -template -void* class_from_python_converter::convertible(PyObject* p) -{ - return objects::find_instance(p); -} - -}}} // namespace boost::python::converter - -#endif // CLASS_DWA20011215_HPP diff --git a/include/boost/python/converter/find_from_python.hpp b/include/boost/python/converter/find_from_python.hpp new file mode 100644 index 00000000..863c44a6 --- /dev/null +++ b/include/boost/python/converter/find_from_python.hpp @@ -0,0 +1,25 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef FIND_FROM_PYTHON_DWA2002223_HPP +# define FIND_FROM_PYTHON_DWA2002223_HPP + +# include +# include + +namespace boost { namespace python { namespace converter { + +struct lvalue_from_python_registration; +struct rvalue_from_python_registration; +struct rvalue_stage1_data; + +BOOST_PYTHON_DECL void* find( + PyObject* source, lvalue_from_python_registration const*); +BOOST_PYTHON_DECL void* find( + PyObject* source, rvalue_from_python_registration const*, rvalue_stage1_data&); + +}}} // namespace boost::python::converter + +#endif // FIND_FROM_PYTHON_DWA2002223_HPP diff --git a/include/boost/python/converter/from_python.hpp b/include/boost/python/converter/from_python.hpp index b6e1edc4..0881a06a 100644 --- a/include/boost/python/converter/from_python.hpp +++ b/include/boost/python/converter/from_python.hpp @@ -6,193 +6,279 @@ #ifndef FROM_PYTHON_DWA2002127_HPP # define FROM_PYTHON_DWA2002127_HPP -# include -# include -# include -# include -# include -# include +# include # include -# include +# include +# include +# include +# include +# include +# include -namespace boost { namespace python { namespace converter { +namespace boost { namespace python { namespace converter { -// The type of convertibility checking functions -typedef void* (*from_python_check)(PyObject*); -typedef void (*from_python_destructor)(from_python_data&); - -// forward declaration -template struct from_python_lookup; - -// from_python -- -// A body class representing a conversion from python to C++. - -struct BOOST_PYTHON_DECL from_python_converter_base : body +struct from_python_base { - from_python_converter_base(type_id_t, from_python_check); // registers + public: // member functions + from_python_base(void* result); + from_python_base(PyObject*, lvalue_from_python_registration const* chain); + bool convertible() const; + + protected: // member functions + void*const& result() const; + + private: // data members + void* m_result; +}; - // Must return non-null iff the conversion will be successful. Any - // non-null pointer is acceptable, and will be passed on to the - // convert() function, so useful data can be stored there. - inline void* convertible(PyObject*) const; - - // Given the head of a from_python converter chain, find the - // converter which can convert p, leaving its intermediate data in - // data. - inline static from_python_converter_base const* - find(from_python_converter_base const*chain, PyObject* p, void*& data); +// Used when T == U*const& +template +struct pointer_const_reference_from_python +{ + pointer_const_reference_from_python(PyObject*); + T operator()(PyObject*) const; + bool convertible() const; private: - from_python_check m_convertible; - from_python_converter_base* m_next; + detail::referent_storage::type m_result; + + static lvalue_from_python_registration*& chain; }; - +// Used when T == U* template -struct from_python_converter : from_python_converter_base +struct pointer_from_python : from_python_base { - public: // types - typedef typename from_python_function::type conversion_function; + pointer_from_python(PyObject*); + T operator()(PyObject*) const; - public: // member functions - from_python_converter(from_python_check, conversion_function, from_python_destructor = 0); - T convert(PyObject*, from_python_data&) const; - void destroy(from_python_data&) const; - - // Find a converter for converting p to a T. - static from_python_converter const* find(PyObject* p, void*& data); - - private: // data members - conversion_function m_convert; - from_python_destructor m_destroy; - - // Keeps the chain of converters which convert from PyObject* to T - static from_python_converter_base*const& chain; + static lvalue_from_python_registration*& chain; }; -// Initialized to refer to a common place in the registry. +// Used when T == U& and (T != V const& or T == W volatile&) template -from_python_converter_base*const& -from_python_converter::chain = registry::from_python_chain(type_id()); - -// ------------------------------------------------------------------------- - -// A class which implements from_python with a registry lookup. -template -struct from_python_lookup // : from_python_base +struct reference_from_python : from_python_base { - public: // types + reference_from_python(PyObject*); + T operator()(PyObject*) const; - public: // member functions - from_python_lookup(PyObject* source); - ~from_python_lookup(); + static lvalue_from_python_registration*& chain; +}; +// ------- rvalue converters --------- + +// Used for the case where T is a non-pointer, non-reference type OR +// is a const non-volatile reference to a non-pointer type. +template +class rvalue_from_python +{ + typedef typename boost::add_reference< + typename boost::add_const::type + >::type result_type; + + public: + rvalue_from_python(PyObject*); + ~rvalue_from_python(); bool convertible() const; - T operator()(PyObject*); - - public: // functions for use by conversion implementations - // Get the converter object - from_python_converter const* converter() const; - private: // data members - typedef typename from_python_intermediate_data::type intermediate_t; - mutable intermediate_t m_intermediate_data; - from_python_converter const* m_converter; + result_type operator()(PyObject*); + + private: + rvalue_data m_data; + static rvalue_from_python_registration*& chain; +}; + +template +struct select_from_python +{ + BOOST_STATIC_CONSTANT( + bool, ptr = is_pointer::value); + + BOOST_STATIC_CONSTANT( + bool, ptr_cref + = boost::python::detail::is_reference_to_pointer::value + && boost::python::detail::is_reference_to_const::value + && !boost::python::detail::is_reference_to_volatile::value); + + + BOOST_STATIC_CONSTANT( + bool, ref = + boost::python::detail::is_reference_to_non_const::value + || boost::python::detail::is_reference_to_volatile::value); + + typedef typename mpl::select_type< + ptr + , pointer_from_python + , typename mpl::select_type< + ptr_cref + , pointer_const_reference_from_python + , typename mpl::select_type< + ref + , reference_from_python + , rvalue_from_python + >::type + >::type + >::type type; }; // // implementations // -inline void* from_python_converter_base::convertible(PyObject* o) const +inline from_python_base::from_python_base(void* result) + : m_result(result) { - return m_convertible(o); } -inline from_python_converter_base const* -from_python_converter_base::find( - from_python_converter_base const* chain, PyObject* p, void*& data) +inline from_python_base::from_python_base( + PyObject* const source + , lvalue_from_python_registration const* chain) + : m_result(find(source, chain)) { - for (from_python_converter_base const* q = chain; q != 0 ; q = q->m_next) - { - void* d = q->convertible(p); - if (d != 0) - { - data = d; - return q; - } - } - return 0; +} + +inline bool from_python_base::convertible() const +{ + return m_result != 0; +} + +inline void*const& from_python_base::result() const +{ + return m_result; +} + +// -------- + +namespace detail +{ + template + inline U& void_ptr_to_reference(void const volatile* p, U&(*)()) + { + return *(U*)p; + } + + template + struct null_ptr_owner + { + static T value; + }; + template T null_ptr_owner::value = 0; + + template + inline U& null_ptr_reference(U&(*)()) + { + return null_ptr_owner::value; + } + + template + inline void write_void_ptr(void const volatile* storage, void* ptr, T*) + { + *(T**)storage = (T*)ptr; + } + + // writes U(ptr) into the storage + template + inline void write_void_ptr_reference(void const volatile* storage, void* ptr, U&(*)()) + { + write_void_ptr(storage, ptr, U(0)); + } } template -inline from_python_converter::from_python_converter( - from_python_check checker - , conversion_function converter - , from_python_destructor destructor // = 0 - ) - : from_python_converter_base(type_id(), checker) - , m_convert(converter) - , m_destroy(destructor) +inline pointer_const_reference_from_python::pointer_const_reference_from_python(PyObject* p) { + detail::write_void_ptr_reference( + m_result.bytes + , p == Py_None ? p : find(p, chain) + , (T(*)())0); +} + +template +inline bool pointer_const_reference_from_python::convertible() const +{ + return detail::void_ptr_to_reference(m_result.bytes, (T(*)())0) != 0; +} +template +inline T pointer_const_reference_from_python::operator()(PyObject* p) const +{ + return (p == Py_None) + ? detail::null_ptr_reference((T(*)())0) + : detail::void_ptr_to_reference(m_result.bytes, (T(*)())0); +} + +template +lvalue_from_python_registration*& pointer_const_reference_from_python::chain + = registry::lvalue_converters(pointer_type_id()); + +// -------- + +template +inline pointer_from_python::pointer_from_python(PyObject* p) + : from_python_base(p == Py_None ? p : find(p, chain)) +{ +} + +template +inline T pointer_from_python::operator()(PyObject* p) const +{ + return (p == Py_None) ? 0 : T(result()); +} + +template +lvalue_from_python_registration*& pointer_from_python::chain + = registry::lvalue_converters(pointer_type_id()); + +// -------- + +template +inline reference_from_python::reference_from_python(PyObject* p) + : from_python_base(find(p,chain)) +{ +} + +template +inline T reference_from_python::operator()(PyObject*) const +{ + return detail::void_ptr_to_reference(result(), (T(*)())0); +} + +template +lvalue_from_python_registration*& reference_from_python::chain + = registry::lvalue_converters(undecorated_type_id()); + +// ------- + +template +inline rvalue_from_python::rvalue_from_python(PyObject* obj) +{ + find(obj, chain, m_data.stage1); +} + +template +inline rvalue_from_python::~rvalue_from_python() +{ + if (m_data.stage1.convertible == m_data.storage.bytes) + python::detail::destroy_reference(m_data.storage.bytes); +} + +template +inline bool rvalue_from_python::convertible() const +{ + return m_data.stage1.convertible != 0; +} + +template +inline typename rvalue_from_python::result_type +rvalue_from_python::operator()(PyObject* p) +{ + if (m_data.stage1.construct != 0) + m_data.stage1.construct(p, &m_data.stage1); + return detail::void_ptr_to_reference(m_data.stage1.convertible, (result_type(*)())0); } template -inline from_python_converter const* -from_python_converter::find(PyObject* p, void*& data) -{ - return static_cast const*>( - from_python_converter_base::find(chain, p, data)); -} - -template -inline T from_python_converter::convert(PyObject* src, from_python_data& data) const -{ - return this->m_convert(src, data); -} - -template -inline void from_python_converter::destroy(from_python_data& data) const -{ - if (this->m_destroy) - { - this->m_destroy(data); - } -} - -template -inline from_python_lookup::from_python_lookup(PyObject* src) - : m_converter( - from_python_converter::find( - src, m_intermediate_data.stage1)) -{ -} - -template -inline from_python_lookup::~from_python_lookup() -{ - if (m_converter != 0) - m_converter->destroy(m_intermediate_data); -} - -template -inline bool from_python_lookup::convertible() const -{ - return this->m_converter != 0; -} - -template -inline T from_python_lookup::operator()(PyObject* obj) -{ - return this->m_converter->convert(obj, m_intermediate_data); -} - -template -inline from_python_converter const* -from_python_lookup::converter() const -{ - return this->m_converter; -} +rvalue_from_python_registration*& rvalue_from_python::chain + = registry::rvalue_converters(undecorated_type_id()); }}} // namespace boost::python::converter diff --git a/include/boost/python/converter/from_python_data.hpp b/include/boost/python/converter/from_python_data.hpp index 3edcbad7..57a3d76e 100644 --- a/include/boost/python/converter/from_python_data.hpp +++ b/include/boost/python/converter/from_python_data.hpp @@ -9,26 +9,20 @@ # include # include # include -# include +# include +# include +# include +# include // Keep these for the metaprogram which EDG is choking on. # if !defined(__EDG__) || (__EDG_VERSION__ > 245) # include # include -# include # include # endif namespace boost { namespace python { namespace converter { -// A POD which is layout-compatible with the real intermediate data -// for all from_python conversions. There may be additional storage if -// we are converting a reference type. -struct from_python_data -{ - void* stage1; -}; - namespace detail { template struct referent_alignment; @@ -74,8 +68,8 @@ namespace detail template struct referent_size { - static T t; - BOOST_STATIC_CONSTANT(std::size_t, value = sizeof(t)); + static T f(); + BOOST_STATIC_CONSTANT(std::size_t, value = sizeof(f())); }; # endif @@ -130,17 +124,13 @@ namespace detail #endif // EDG is too slow template - struct aligned_storage + union aligned_storage { - typedef Align align_t; - union - { - Align align; - char bytes[size - // this is just a STATIC_ASSERT. For some reason - // MSVC was barfing on the boost one. - - (is_same::value ? size : 0)]; - }; + Align align; + char bytes[size + // this is just a STATIC_ASSERT. For some reason + // MSVC was barfing on the boost one. + - (is_same::value ? size : 0)]; }; template @@ -151,56 +141,39 @@ namespace detail typedef mpl::for_each< align_types , unknown_alignment - , best_alignment_type::value> + , best_alignment_type< + referent_alignment::value + > > loop; + typedef typename loop::state align_t; #else // The Python source makes the assumption that double has // maximal alignment anyway typedef double align_t; -#endif - + +#endif + BOOST_STATIC_CONSTANT(std::size_t, alignment1 = alignment_of::value); + BOOST_STATIC_CONSTANT(std::size_t, alignment2 = referent_alignment::value); + + BOOST_STATIC_ASSERT(alignment1 >= alignment2); + BOOST_STATIC_ASSERT(alignment1 % alignment2 == 0); + typedef aligned_storage::value> type; }; - - template - struct intermediate_data : from_python_data - { - typename referent_storage::type stage2; - }; - - template <> - struct intermediate_data : from_python_data - { - }; - + } -// ------------------------------------------------------------------------- -// Auxiliary POD storage where the convertible and/or convert functions of a -// from_python object may place arbitrary data. -// -// Always starts with a void* -// -// For references, we produce additional aligned storage sufficient to -// store the referent - template -struct from_python_intermediate_data +struct rvalue_data { - typedef typename mpl::select_type< - is_reference::value, T, void>::type just_reference_t; - - typedef detail::intermediate_data type; + rvalue_stage1_data stage1; + + typename detail::referent_storage< + typename add_reference::type + >::type storage; }; -template -void* get_storage(from_python_data& x, boost::type* = 0) -{ - typedef typename from_python_intermediate_data::type layout; - return static_cast(&x)->stage2.bytes; -} - }}} // namespace boost::python::converter #endif // FROM_PYTHON_AUX_DATA_DWA2002128_HPP diff --git a/include/boost/python/converter/from_python_function.hpp b/include/boost/python/converter/from_python_function.hpp index 0cf90459..eea96372 100644 --- a/include/boost/python/converter/from_python_function.hpp +++ b/include/boost/python/converter/from_python_function.hpp @@ -10,13 +10,8 @@ namespace boost { namespace python { namespace converter { -struct from_python_data; - -template -struct from_python_function -{ - typedef T (*type)(PyObject*, from_python_data&); -}; +struct rvalue_stage1_data; +typedef void (*constructor_function)(PyObject* source, rvalue_stage1_data*); }}} // namespace boost::python::converter diff --git a/include/boost/python/converter/from_python_stage1_data.hpp b/include/boost/python/converter/from_python_stage1_data.hpp new file mode 100644 index 00000000..50fd74ad --- /dev/null +++ b/include/boost/python/converter/from_python_stage1_data.hpp @@ -0,0 +1,21 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef FROM_PYTHON_STAGE1_DATA_DWA2002223_HPP +# define FROM_PYTHON_STAGE1_DATA_DWA2002223_HPP + +# include + +namespace boost { namespace python { namespace converter { + +struct rvalue_stage1_data +{ + void* convertible; + constructor_function construct; +}; + +}}} // namespace boost::python::converter + +#endif // FROM_PYTHON_STAGE1_DATA_DWA2002223_HPP diff --git a/include/boost/python/converter/registrations.hpp b/include/boost/python/converter/registrations.hpp new file mode 100644 index 00000000..8a27741c --- /dev/null +++ b/include/boost/python/converter/registrations.hpp @@ -0,0 +1,28 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef REGISTRATIONS_DWA2002223_HPP +# define REGISTRATIONS_DWA2002223_HPP + +# include + +namespace boost { namespace python { namespace converter { + +struct lvalue_from_python_registration +{ + void* (*convert)(PyObject* source); + lvalue_from_python_registration* next; +}; + +struct rvalue_from_python_registration +{ + void* (*convertible)(PyObject*); + constructor_function construct; + rvalue_from_python_registration* next; +}; + +}}} // namespace boost::python::converter + +#endif // REGISTRATIONS_DWA2002223_HPP diff --git a/include/boost/python/converter/registry.hpp b/include/boost/python/converter/registry.hpp index bdb64254..a511a1a4 100644 --- a/include/boost/python/converter/registry.hpp +++ b/include/boost/python/converter/registry.hpp @@ -9,20 +9,33 @@ # include # include # include +# include namespace boost { namespace python { namespace converter { -struct BOOST_PYTHON_DECL from_python_converter_base; +struct lvalue_from_python_registration; +struct rvalue_from_python_registration; // This namespace acts as a sort of singleton namespace registry { + BOOST_PYTHON_DECL lvalue_from_python_registration*& lvalue_converters(undecorated_type_id_t); + BOOST_PYTHON_DECL rvalue_from_python_registration*& rvalue_converters(undecorated_type_id_t); + BOOST_PYTHON_DECL to_python_value_function const& to_python_function(undecorated_type_id_t); BOOST_PYTHON_DECL void insert(to_python_value_function, undecorated_type_id_t); - - BOOST_PYTHON_DECL from_python_converter_base*& from_python_chain(type_id_t); + + // Insert an lvalue from_python converter + BOOST_PYTHON_DECL void insert(void* (*convert)(PyObject*), undecorated_type_id_t); + + // Insert an rvalue from_python converter + BOOST_PYTHON_DECL void insert( + void* (*convertible)(PyObject*) + , constructor_function + , undecorated_type_id_t + ); BOOST_PYTHON_DECL PyTypeObject*& class_object(undecorated_type_id_t key); } diff --git a/include/boost/python/converter/target.hpp b/include/boost/python/converter/target.hpp deleted file mode 100644 index f8f33171..00000000 --- a/include/boost/python/converter/target.hpp +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright David Abrahams 2001. Permission to copy, use, -// modify, sell and distribute this software is granted provided this -// copyright notice appears in all copies. This software is provided -// "as is" without express or implied warranty, and with no claim as -// to its suitability for any purpose. - -#ifndef TARGET_DWA20011119_HPP -# define TARGET_DWA20011119_HPP -# include -# include -# include -# include -# include - -namespace boost { namespace python { namespace converter { - -// target -- -// -// This type generator (see -// ../../../more/generic_programming.html#type_generator) is used -// to select the return type of the appropriate converter for -// unwrapping a given type. - -// Strategy: -// -// 1. reduce everything to a common, un-cv-qualified reference -// type where possible. This will save on registering many different -// converter types. -// -// 2. Treat built-in types specially: when unwrapping a value or -// constant reference to one of these, use a value for the target -// type. It will bind to a const reference if neccessary, and more -// importantly, avoids having to dynamically allocate room for -// an lvalue of types which can be cheaply copied. -// - -// Target Source -// int int -// int const& int -// int& int& -// int volatile& int volatile& -// int const volatile& int const volatile& - -// On compilers supporting partial specialization: -// -// Target Source -// T T const& -// T& T& -// T const& T const& -// T volatile T& -// T const volatile& T const& -// T* T* -// T const* T const* -// T volatile T* -// T const volatile* T const* -// T cv*const& same as T cv* -// T cv*& T*& <- should this be legal? -// T cv*volatile& T*& <- should this be legal? -// T cv*const volatile& T*& <- should this be legal? - -// On others: -// -// Target Source -// T T& -// T cv& T cv& -// T cv* T cv* -// T cv*cv& T cv*cv& - -// As you can see, in order to handle the same range of types without -// partial specialization, more converters need to be registered. - -template -struct target -{ - // Some pointer types are handled in a more sophisticated way on - // compilers supporting partial specialization. - BOOST_STATIC_CONSTANT(bool, use_identity = (::boost::is_scalar::value)); - - typedef typename mpl::select_type< - use_identity - , T - , typename add_reference< - typename add_const< - typename remove_volatile::type - >::type - >::type - >::type type; -}; - -// When partial specialization is not present, we'll simply need to -// register many more converters. -# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - -template -struct target -{ - typedef typename remove_volatile::type& type; -}; - -template -struct target -{ - typedef typename boost::mpl::select_type< - is_scalar::value - , typename remove_cv::type - , typename remove_volatile::type const& - >::type type; -}; - -template -struct target -{ - typedef typename remove_volatile::type* type; -}; - -// Handle T*-cv for completeness. Function arguments in a signature -// are never actually cv-qualified, but who knows how these converters -// might be used, or whether compiler bugs lurk which make it seem -// otherwise? -template -struct target -{ - typedef typename remove_volatile::type* type; -}; - -template -struct target -{ - typedef typename remove_volatile::type* type; -}; - -template -struct target -{ - typedef typename remove_volatile::type* type; -}; - -// non-const references to pointers should be handled by the -// specialization for T&, above. -template -struct target -{ - typedef typename remove_volatile::type* type; -}; -# endif - -// Fortunately, we can handle T const& where T is an arithmetic type -// by explicit specialization. These specializations will cause value -// and const& arguments to be converted to values, rather than to -// references. -# define BOOST_PYTHON_UNWRAP_VALUE(T) \ -template <> \ -struct target \ -{ \ - typedef T type; \ -}; \ -template <> \ -struct target \ -{ \ - typedef T type; \ -}; \ -template <> \ -struct target \ -{ \ - typedef T type; \ -}; \ -template <> \ -struct target \ -{ \ - typedef T type; \ -}; \ -template <> \ -struct target \ -{ \ - typedef T type; \ -} - -BOOST_PYTHON_UNWRAP_VALUE(char); -BOOST_PYTHON_UNWRAP_VALUE(unsigned char); -BOOST_PYTHON_UNWRAP_VALUE(signed char); -BOOST_PYTHON_UNWRAP_VALUE(unsigned int); -BOOST_PYTHON_UNWRAP_VALUE(signed int); -BOOST_PYTHON_UNWRAP_VALUE(unsigned short); -BOOST_PYTHON_UNWRAP_VALUE(signed short); -BOOST_PYTHON_UNWRAP_VALUE(unsigned long); -BOOST_PYTHON_UNWRAP_VALUE(signed long); -BOOST_PYTHON_UNWRAP_VALUE(char const*); - -}}} // namespace boost::python::converter - -#endif // TARGET_DWA20011119_HPP diff --git a/include/boost/python/converter/unwrapper_base.hpp b/include/boost/python/converter/unwrapper_base.hpp deleted file mode 100644 index ea437eb2..00000000 --- a/include/boost/python/converter/unwrapper_base.hpp +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright David Abrahams 2001. Permission to copy, use, -// modify, sell and distribute this software is granted provided this -// copyright notice appears in all copies. This software is provided -// "as is" without express or implied warranty, and with no claim as -// to its suitability for any purpose. -#ifndef UNWRAPPER_BASE_DWA20011215_HPP -# define UNWRAPPER_BASE_DWA20011215_HPP -# include -# include -# include -# include - -namespace boost { namespace python { namespace converter { - -struct BOOST_PYTHON_DECL unwrapper_base : body -{ - public: - unwrapper_base(type_id_t); // registers - ~unwrapper_base(); // unregisters - - // Must return non-null iff the conversion will be successful. Any - // non-null pointer is acceptable, and will be passed on to the - // convert() function, so useful data can be stored there. - virtual void* can_convert(PyObject*) const = 0; - - protected: - // this is an arbitrary non-null pointer you can use to indicate success - static void* const non_null; - - private: // body required interface implementation - void destroy_handle(handle*) const {} -}; - -}}} // namespace boost::python::converter - -#endif // UNWRAPPER_BASE_DWA20011215_HPP diff --git a/include/boost/python/detail/destroy.hpp b/include/boost/python/detail/destroy.hpp new file mode 100644 index 00000000..07738e2f --- /dev/null +++ b/include/boost/python/detail/destroy.hpp @@ -0,0 +1,83 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef DESTROY_DWA2002221_HPP +# define DESTROY_DWA2002221_HPP + +# include +# include + +namespace boost { namespace python { namespace detail { + +template struct value_destroyer; + +template <> +struct value_destroyer +{ + template + static void execute(T const volatile* p) + { + p->T::~T(); + } +}; + +template <> +struct value_destroyer +{ + template + static void execute(A*, T const volatile* const first) + { + for (T const volatile* p = first; p != first + sizeof(A)/sizeof(T); ++p) + value_destroyer< + boost::is_array::value + ,boost::has_trivial_destructor::value + >::execute(p); + } + + template + static void execute(T const volatile* p) + { + execute(p, *p); + } +}; + +template <> +struct value_destroyer +{ + template + static void execute(T const volatile* p) + { + } +}; + +template <> +struct value_destroyer +{ + template + static void execute(T const volatile* p) + { + } +}; + +template +inline void destroy_reference_impl(void* p, T& (*)()) +{ + // note: cv-qualification needed for MSVC6 + // must come *before* T for metrowerks + value_destroyer< + (boost::is_array::value) + , (boost::has_trivial_destructor::value) + >::execute((const volatile T*)p); +} + +template +inline void destroy_reference(void* p, T(*)() = 0) +{ + destroy_reference_impl(p, (T(*)())0); +} + +}}} // namespace boost::python::detail + +#endif // DESTROY_DWA2002221_HPP diff --git a/include/boost/python/from_python.hpp b/include/boost/python/from_python.hpp index 995f7877..62b340f1 100644 --- a/include/boost/python/from_python.hpp +++ b/include/boost/python/from_python.hpp @@ -7,15 +7,14 @@ # define FROM_PYTHON_DWA2002128_HPP # include -# include namespace boost { namespace python { template struct from_python - : converter::from_python_lookup::type> + : converter::select_from_python::type { - typedef converter::from_python_lookup::type> base; + typedef typename converter::select_from_python::type base; from_python(PyObject*); }; diff --git a/include/boost/python/lvalue_from_python.hpp b/include/boost/python/lvalue_from_python.hpp deleted file mode 100644 index c5d09ff5..00000000 --- a/include/boost/python/lvalue_from_python.hpp +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright David Abrahams 2002. Permission to copy, use, -// modify, sell and distribute this software is granted provided this -// copyright notice appears in all copies. This software is provided -// "as is" without express or implied warranty, and with no claim as -// to its suitability for any purpose. -#ifndef LVALUE_FROM_PYTHON_DWA2002130_HPP -# define LVALUE_FROM_PYTHON_DWA2002130_HPP - -# include -# include - -namespace boost { namespace python { - -// Utility which produces a member extractor function on platforms -// other than VC6. -template -struct get_member -{ - static Member& execute(Class& c) - { - return c.*mp; - } -}; - -namespace detail -{ - template - struct extract_identity - { - static Class& execute(Class& c) - { - return c; - } - }; -} - -template < - PyTypeObject const* python_type - , class Value - , class PythonObject = Value - , class Extract = detail::extract_identity - > -class lvalue_from_python -{ - typedef type_from_python convertible_t; - public: - - lvalue_from_python() - : m_mutable_converter( - &convertible_t::convertible, convert_mutable) - - , m_const_converter( - &convertible_t::convertible, convert_const) - - , m_mutable_pointer_converter( - &convertible_t::convertible, convert_mutable_pointer) - - , m_const_pointer_converter( - &convertible_t::convertible, convert_const_pointer) - {} - - private: - static Value& convert_mutable(PyObject* op, converter::from_python_data&) - { - return Extract::execute(*(PythonObject*)op); - } - - static Value const& convert_const(PyObject* op, converter::from_python_data&) - { - return Extract::execute(*(PythonObject*)op); - } - - static Value* convert_mutable_pointer(PyObject* op, converter::from_python_data&) - { - return &Extract::execute(*(PythonObject*)op); - } - - static Value const* convert_const_pointer(PyObject* op, converter::from_python_data&) - { - return &Extract::execute(*(PythonObject*)op); - } - - typedef converter::from_python_converter mutable_converter; - typedef converter::from_python_converter const_converter; - typedef converter::from_python_converter mutable_pointer_converter; - typedef converter::from_python_converter const_pointer_converter; - - mutable_converter m_mutable_converter; - const_converter m_const_converter; - mutable_pointer_converter m_mutable_pointer_converter; - const_pointer_converter m_const_pointer_converter; -}; - -}} // namespace boost::python - -#endif // LVALUE_FROM_PYTHON_DWA2002130_HPP diff --git a/include/boost/python/object/class.hpp b/include/boost/python/object/class.hpp index 35280074..04f0e992 100644 --- a/include/boost/python/object/class.hpp +++ b/include/boost/python/object/class.hpp @@ -53,7 +53,7 @@ struct BOOST_PYTHON_DECL instance_holder : private noncopyable // return the next holder in a chain instance_holder* next() const; - virtual void* holds(converter::type_id_t) = 0; + virtual void* holds(converter::undecorated_type_id_t) = 0; void install(PyObject* inst) throw(); @@ -85,15 +85,19 @@ struct instance instance_holder* objects; }; -// Given a type_id, find the instance data which corresponds to it, or -// return 0 in case no such type is held. -BOOST_PYTHON_DECL void* find_instance_impl(PyObject*, converter::type_id_t); +// Given an undecorated type_id, find the instance data which +// corresponds to it, or return 0 in case no such type is held. +BOOST_PYTHON_DECL void* find_instance_impl(PyObject*, converter::undecorated_type_id_t); +// This produces a function with the right signature for use in from_python conversions template -T* find_instance(PyObject* p, T* = 0) +struct instance_finder { - return static_cast(find_instance_impl(p, converter::type_id())); -} + static inline void* execute(PyObject* p) + { + return find_instance_impl(p, converter::undecorated_type_id()); + } +}; BOOST_PYTHON_DECL ref class_metatype(); BOOST_PYTHON_DECL ref class_type(); diff --git a/include/boost/python/object/class_converters.hpp b/include/boost/python/object/class_converters.hpp index d5978af7..540565bf 100644 --- a/include/boost/python/object/class_converters.hpp +++ b/include/boost/python/object/class_converters.hpp @@ -6,10 +6,10 @@ #ifndef CLASS_CONVERTERS_DWA2002119_HPP # define CLASS_CONVERTERS_DWA2002119_HPP -# include # include # include # include +# include namespace boost { namespace python { namespace objects { @@ -24,7 +24,6 @@ struct class_converters class_converters(ref const& python_class); private: // data members - converter::class_from_python_converter m_unwrapper; class_wrapper m_wrapper; }; @@ -90,6 +89,10 @@ template class_converters::class_converters(ref const& type_object) : m_wrapper(type_object) { + converter::registry::insert( + &instance_finder::execute + , converter::undecorated_type_id()); + // register all up/downcasts here register_dynamic_id(); diff --git a/include/boost/python/object/pointer_holder.hpp b/include/boost/python/object/pointer_holder.hpp index 21fe8e96..c307f019 100644 --- a/include/boost/python/object/pointer_holder.hpp +++ b/include/boost/python/object/pointer_holder.hpp @@ -139,7 +139,7 @@ struct pointer_holder : instance_holder {} private: // required holder implementation - void* holds(converter::type_id_t); + void* holds(converter::undecorated_type_id_t); private: // data members Pointer m_p; @@ -186,12 +186,12 @@ pointer_holder::pointer_holder(Pointer p) } template -void* pointer_holder::holds(converter::type_id_t dst_t) +void* pointer_holder::holds(converter::undecorated_type_id_t dst_t) { - if (dst_t == converter::type_id()) + if (dst_t == converter::undecorated_type_id()) return &this->m_p; - converter::type_id_t src_t = converter::type_id(); + converter::type_id_t src_t = converter::undecorated_type_id(); return src_t == dst_t ? &*this->m_p : find_dynamic_type(&*this->m_p, src_t, dst_t); } diff --git a/include/boost/python/object/value_holder.hpp b/include/boost/python/object/value_holder.hpp index 01431370..6533bc39 100644 --- a/include/boost/python/object/value_holder.hpp +++ b/include/boost/python/object/value_holder.hpp @@ -134,7 +134,7 @@ struct value_holder : instance_holder {} private: // required holder implementation - void* holds(converter::type_id_t); + void* holds(converter::undecorated_type_id_t); private: // data members Held m_held; @@ -151,9 +151,9 @@ struct value_holder_generator }; template -void* value_holder::holds(converter::type_id_t dst_t) +void* value_holder::holds(converter::undecorated_type_id_t dst_t) { - converter::type_id_t src_t = converter::type_id(); + converter::undecorated_type_id_t src_t = converter::undecorated_type_id(); return src_t == dst_t ? &m_held : find_static_type(&m_held, src_t, dst_t); } diff --git a/include/boost/python/reference_from_python.hpp b/include/boost/python/reference_from_python.hpp deleted file mode 100644 index a9631dc5..00000000 --- a/include/boost/python/reference_from_python.hpp +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright David Abrahams 2002. Permission to copy, use, -// modify, sell and distribute this software is granted provided this -// copyright notice appears in all copies. This software is provided -// "as is" without express or implied warranty, and with no claim as -// to its suitability for any purpose. -#ifndef REFERENCE_FROM_PYTHON_DWA2002130_HPP -# define REFERENCE_FROM_PYTHON_DWA2002130_HPP - -# include -# include - -namespace boost { namespace python { - -// Utility which produces a member extractor function on platforms -// other than VC6. -template -struct get_member -{ - static Member& execute(Class* c) - { - return c->*mp; - } -}; - -template < - PyTypeObject const* python_type - , class Value - , class PythonObject - , class Extract - > -struct reference_from_python -{ - typedef type_from_python convertible_t; - - reference_from_python() - : m_mutable_converter( - &convertible_t::convertible, convert_mutable) - - , m_const_converter( - &convertible_t::convertible, convert_const) - {} - - static Value& convert_mutable(PyObject* op, converter::from_python_data&) - { - return Extract::execute(*(PythonObject*)op); - } - - static Value const& convert_const(PyObject* op, converter::from_python_data&) - { - return Extract::execute(*(PythonObject*)op); - } - - private: - typedef converter::from_python_converter mutable_converter; - typedef converter::from_python_converter const_converter; - mutable_converter m_mutable_converter; - const_converter m_const_converter; -}; - -}} // namespace boost::python - -#endif // REFERENCE_FROM_PYTHON_DWA2002130_HPP diff --git a/include/boost/python/type_from_python.hpp b/include/boost/python/type_from_python.hpp index 46d59d13..16b8da81 100644 --- a/include/boost/python/type_from_python.hpp +++ b/include/boost/python/type_from_python.hpp @@ -6,15 +6,94 @@ #ifndef TYPE_FROM_PYTHON_DWA2002130_HPP # define TYPE_FROM_PYTHON_DWA2002130_HPP +# include + namespace boost { namespace python { -template +namespace detail +{ + // Given a pointer-to-function of 1 parameter returning a reference + // type, return the type_id of the function's return type. + template + inline converter::undecorated_type_id_t extractor_type_id(T&(*)(U)) + { + return converter::undecorated_type_id(); + } + + // A function generator whose static execute() function is an lvalue + // from_python converter using the given Extractor. U is exepcted to + // be the actual type of the PyObject instance from which the result + // is being extracted. + template + struct normalized_extractor + { + static inline void* execute(PyObject* op) + { + typedef typename boost::add_reference::type param; + return &Extractor::execute( + boost::python::converter::detail::void_ptr_to_reference( + op, (param(*)())0 ) + ); + } + }; + + // Given an Extractor type and a pointer to its execute function, + // return a new object whose static execute function does the same + // job but is a conforming lvalue from_python conversion function. + // + // usage: normalize(&Extractor::execute) + template + inline normalized_extractor + normalize(T(*)(U), Extractor* = 0) + { + return normalized_extractor(); + } +} + +// An Extractor which extracts the given member from a Python object +// whose instances are stored as InstanceType. +template +struct member_extractor +{ + static MemberType& execute(InstanceType& c) + { + (void)c.ob_type; // static assertion + return c.*member; + } +}; + +// An Extractor which simply extracts the entire python object +// instance of InstanceType. +template +struct identity_extractor +{ + static InstanceType& execute(InstanceType& c) + { + (void)c.ob_type; // static assertion + return c; + } +}; + +// Registers a from_python conversion which extracts lvalues using +// Extractor's static execute function from Python objects whose type +// object is python_type. +template struct type_from_python { - static void* convertible(PyObject* op) + type_from_python() { - return PyObject_TypeCheck( - op, const_cast(python_type)) ? op : 0; + converter::registry::insert( + &extract, detail::extractor_type_id(&Extractor::execute)); + } + + static void* extract(PyObject* op) + { + return PyObject_TypeCheck(op, const_cast(python_type)) + ? const_cast( + static_cast( + detail::normalize(&Extractor::execute).execute(op))) + : 0 + ; } }; diff --git a/include/boost/python/value_from_python.hpp b/include/boost/python/value_from_python.hpp deleted file mode 100644 index c835de45..00000000 --- a/include/boost/python/value_from_python.hpp +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright David Abrahams 2002. Permission to copy, use, -// modify, sell and distribute this software is granted provided this -// copyright notice appears in all copies. This software is provided -// "as is" without express or implied warranty, and with no claim as -// to its suitability for any purpose. -#ifndef VALUE_FROM_PYTHON_DWA2002130_HPP -# define VALUE_FROM_PYTHON_DWA2002130_HPP - -# include -# include -# include -# include - -namespace boost { namespace python { - -template -struct value_from_python -{ - typedef value_from_python self; - typedef converter::from_python_check from_python_check; - - value_from_python(from_python_check convertible) - : m_converter( - convertible - , &Derived::convert - - // Change this to a compile-time check later to avoid - // generating destroy function - , has_trivial_destructor::value ? 0 : &Derived::destroy - ) - { - } - - value_from_python() - : m_converter( - &Derived::convertible - , &Derived::convert - - // Change this to a compile-time check later to avoid - // generating destroy function - , has_trivial_destructor::value ? 0 : &Derived::destroy - ) - { - } - - static void* get_storage(converter::from_python_data& data) - { - return converter::get_storage(data); - } - - // Mark successful construction - static void constructed(converter::from_python_data& data) - { - data.stage1 = self::get_storage(data); - } - - inline static void destroy(converter::from_python_data& data) - { - // Get the location of the storage for - void* storage = self::get_storage(data); - - // Check for successful construction - if (data.stage1 == storage) - static_cast(storage)->~T(); - } - - private: - converter::from_python_converter m_converter; -}; - -}} // namespace boost::python - -#endif // VALUE_FROM_PYTHON_DWA2002130_HPP diff --git a/src/converter/body.cpp b/src/converter/body.cpp deleted file mode 100644 index 637f8c3e..00000000 --- a/src/converter/body.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright David Abrahams 2001. Permission to copy, use, -// modify, sell and distribute this software is granted provided this -// copyright notice appears in all copies. This software is provided -// "as is" without express or implied warranty, and with no claim as -// to its suitability for any purpose. -#include - -namespace boost { namespace python { namespace converter { - -// default implementation is a no-op. Most handles will not hold any -// data that needs to be managed. Unwrap objects which convert -// by-value are an exception. Fortunately, the concrete body subclass -// has that knowledge. -void body::destroy_handle(handle*) const -{ -} - -}}} // namespace boost::python::converter diff --git a/src/converter/builtin_converters.cpp b/src/converter/builtin_converters.cpp index 9cf5f110..8db20586 100644 --- a/src/converter/builtin_converters.cpp +++ b/src/converter/builtin_converters.cpp @@ -7,177 +7,120 @@ #include #include #include -#include -#include #include +#include #include #include -//#include #include namespace boost { namespace python { namespace converter { namespace { - // Only an object which we know is holding a char const* can be - // converted to one - struct convertible_to_cstring + // An lvalue conversion function which extracts a char const* from a + // Python String. + void* convert_to_cstring(PyObject* obj) { - static unaryfunc* execute(PyObject* obj) - { - return PyString_Check(obj) ? &obj->ob_type->tp_str : 0; - } - }; + return PyString_Check(obj) ? PyString_AsString(obj) : 0; + } - struct extract_cstring + // Given a target type and a SlotPolicy describing how to perform a + // given conversion, registers from_python converters which use the + // SlotPolicy to extract the type. + template + struct slot_rvalue_from_python { - static char const* execute(PyObject* obj) - { - return PyString_AsString(obj); - } - }; - - // Any object which can be converted to a Python string can also be - // converted to a C++ string, since the latter owns its bytes. - struct convertible_to_string - { - static unaryfunc* execute(PyObject* obj) - { - return obj->ob_type->tp_str ? &obj->ob_type->tp_str : 0; - } - }; - - // Transform a function returning a unaryfunc* into one that returns a void* - template - struct return_void_ptr - { - static void* execute(PyObject* p) { return F::execute(p); } - }; - - template < - class T // The target type - , class Convertible // returns a pointer to a unaryfunc producing an object - , class TExtract // ...from which TExtract extracts T's constructor argument - > - struct tp_scalar_from_python - : from_python_converter - { - private: - typedef return_void_ptr convertible_fn; - public: - tp_scalar_from_python() - : from_python_converter( - &convertible_fn::execute - , convert) - {} - - static T convert(PyObject* obj, from_python_data& data) + slot_rvalue_from_python() { - unaryfunc converter = *(unaryfunc*)data.stage1; - ref converted(converter(obj)); - return TExtract::execute(converted.get()); + registry::insert( + &slot_rvalue_from_python::convertible + , &slot_rvalue_from_python::construct + , undecorated_type_id() + ); } - }; - - // Extract a reference to T using the functions in the source - // object's type slots - template < - class T // The target type - , class Convertible // returns a pointer to a unaryfunc producing an object - , class TExtract // ...from which TExtract extracts T's constructor argument - > - struct tp_cref_from_python - : value_from_python > - { + private: - typedef tp_cref_from_python self; - typedef value_from_python > base; - - public: - tp_cref_from_python() - : base(&return_void_ptr::execute) - {} - - static T const& convert(PyObject* obj, from_python_data& data) + static void* convertible(PyObject* obj) { - unaryfunc converter = *(unaryfunc*)data.stage1; - - void* storage = self::get_storage(data); - - ref converted(converter(obj)); - - T* const p = new (storage) T(TExtract::execute(converted.get())); - - // note that construction is successful. - data.stage1 = p; - - return *p; + unaryfunc* slot = SlotPolicy::get_slot(obj); + return slot && *slot ? slot : 0; + } + + static void construct(PyObject* obj, rvalue_stage1_data* data) + { + // Get the (intermediate) source object + unaryfunc creator = *static_cast(data->convertible); + ref intermediate(creator(obj)); + + // Get the location in which to construct + void* storage = ((rvalue_data*)data)->storage.bytes; + new (storage) T(SlotPolicy::extract(intermediate.get())); + + // record successful construction + data->convertible = storage; } }; - struct convertible_to_int + // A SlotPolicy for extracting integer types from Python objects + struct int_rvalue_from_python { - static unaryfunc* execute(PyObject* obj) + static unaryfunc* get_slot(PyObject* obj) { PyNumberMethods* number_methods = obj->ob_type->tp_as_number; if (number_methods == 0) return 0; // For floating types, return the float conversion slot to avoid - // creating a new object. We'll handle that in - // py_int_or_float_as_long, below + // creating a new object. We'll handle that below if (PyObject_TypeCheck(obj, &PyFloat_Type) && number_methods->nb_float) return &number_methods->nb_float; - return number_methods && number_methods->nb_int - ? &number_methods->nb_int : 0; + return &number_methods->nb_int; } - }; - - struct py_int_or_float_as_long - { - static long execute(PyObject* obj) + + static long extract(PyObject* intermediate) { - if (PyObject_TypeCheck(obj, &PyFloat_Type)) + if (PyObject_TypeCheck(intermediate, &PyFloat_Type)) { - return numeric_cast(PyFloat_AS_DOUBLE(obj)); + return numeric_cast(PyFloat_AS_DOUBLE(intermediate)); } else { - return PyInt_AS_LONG(obj); + return PyInt_AS_LONG(intermediate); } } }; + + // identity_unaryfunc/non_null -- manufacture a unaryfunc "slot" + // which just returns its argument. Used for bool conversions, since + // all Python objects are directly convertible to bool extern "C" PyObject* identity_unaryfunc(PyObject* x) { Py_INCREF(x); return x; } - unaryfunc non_null = identity_unaryfunc; - - struct convertible_to_bool + + // A SlotPolicy for extracting bool from a Python object + struct bool_rvalue_from_python { - static unaryfunc* execute(PyObject* obj) + static unaryfunc* get_slot(PyObject*) { return &non_null; } - }; - - struct py_object_as_bool - { - static bool execute(PyObject* obj) + + static bool extract(PyObject* intermediate) { - return PyObject_IsTrue(obj); + return PyObject_IsTrue(intermediate); } }; - - struct convertible_to_double + // A SlotPolicy for extracting floating types from Python objects. + struct float_rvalue_from_python { - static unaryfunc* execute(PyObject* obj) + static unaryfunc* get_slot(PyObject* obj) { PyNumberMethods* number_methods = obj->ob_type->tp_as_number; if (number_methods == 0) @@ -189,67 +132,63 @@ namespace if (PyObject_TypeCheck(obj, &PyInt_Type) && number_methods->nb_int) return &number_methods->nb_int; - return number_methods && number_methods->nb_float - ? &number_methods->nb_float : 0; + return &number_methods->nb_float; } - }; - - struct py_float_or_int_as_double - { - static double execute(PyObject* obj) + + static double extract(PyObject* intermediate) { - if (PyObject_TypeCheck(obj, &PyInt_Type)) + if (PyObject_TypeCheck(intermediate, &PyInt_Type)) { - return PyInt_AS_LONG(obj); + return PyInt_AS_LONG(intermediate); } else { - return PyFloat_AS_DOUBLE(obj); + return PyFloat_AS_DOUBLE(intermediate); } } }; - template - struct scalar_from_python + // A SlotPolicy for extracting C++ strings from Python objects. + struct string_rvalue_from_python { - tp_cref_from_python cref_converter; - tp_scalar_from_python value_converter; - }; - - template - void register_int_converters(T* = 0) - { - static scalar_from_python x; - } -} + // If the underlying object is "string-able" this will succeed + static unaryfunc* get_slot(PyObject* obj) + { + return &obj->ob_type->tp_str; + }; -#define REGISTER_INT_CONVERTERS(U) register_int_converters() + // Remember that this will be used to construct the result object + static char const* extract(PyObject* intermediate) + { + return PyString_AsString(intermediate); + } + }; +} + +#define REGISTER_INT_CONVERTERS(U) slot_rvalue_from_python() #define REGISTER_INT_CONVERTERS2(U) REGISTER_INT_CONVERTERS(signed U); REGISTER_INT_CONVERTERS(unsigned U) void initialize_builtin_converters() { - static scalar_from_python< - bool, convertible_to_bool, py_object_as_bool> bool_from_python; - + // booleans + slot_rvalue_from_python(); + + // integer types REGISTER_INT_CONVERTERS2(char); REGISTER_INT_CONVERTERS2(short); REGISTER_INT_CONVERTERS2(int); REGISTER_INT_CONVERTERS2(long); - static scalar_from_python< - float,convertible_to_double,py_float_or_int_as_double> float_from_python; + // floating types + slot_rvalue_from_python(); + slot_rvalue_from_python(); + slot_rvalue_from_python(); - static scalar_from_python< - double,convertible_to_double,py_float_or_int_as_double> double_from_python; - - static scalar_from_python< - long double,convertible_to_double,py_float_or_int_as_double> long_double_from_python; - - static scalar_from_python< - char const*, convertible_to_cstring, extract_cstring> cstring_from_python; + // Add an lvalue converter for char which gets us char const* + registry::insert(convert_to_cstring,undecorated_type_id()); - static tp_cref_from_python< - std::string, convertible_to_string, extract_cstring> string_from_python; + // Register by-value converters to std::string + slot_rvalue_from_python(); } }}} // namespace boost::python::converter diff --git a/src/converter/from_python.cpp b/src/converter/from_python.cpp index 2e844acf..0650fcbb 100644 --- a/src/converter/from_python.cpp +++ b/src/converter/from_python.cpp @@ -4,23 +4,40 @@ // "as is" without express or implied warranty, and with no claim as // to its suitability for any purpose. -#include -#include +#include +#include +#include namespace boost { namespace python { namespace converter { -from_python_converter_base::from_python_converter_base( - type_id_t type - , from_python_check checker - ) - : body(type) - , m_convertible(checker) - +BOOST_PYTHON_DECL void* find( + PyObject* source + , rvalue_from_python_registration const* chain + , rvalue_stage1_data& data) { - // Insert this in the converter chain. - from_python_converter_base*& head = registry::from_python_chain(type); - m_next = head; - head = this; + for (;chain != 0; chain = chain->next) + { + void* r = chain->convertible(source); + if (r != 0) + { + data.construct = chain->construct; + return data.convertible = r; + } + } + return data.convertible = 0; +} + +BOOST_PYTHON_DECL void* find( + PyObject* const source + , lvalue_from_python_registration const* chain) +{ + for (;chain != 0; chain = chain->next) + { + void* r = chain->convert(source); + if (r != 0) + return r; + } + return 0; } }}} // namespace boost::python::converter diff --git a/src/converter/handle.cpp b/src/converter/handle.cpp deleted file mode 100644 index 1a2b8c31..00000000 --- a/src/converter/handle.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright David Abrahams 2001. Permission to copy, use, -// modify, sell and distribute this software is granted provided this -// copyright notice appears in all copies. This software is provided -// "as is" without express or implied warranty, and with no claim as -// to its suitability for any purpose. -#include -#include - -namespace boost { namespace python { namespace converter { - -bool handle::convertible() const -{ - for (handle const* p = this; p != 0; p = p->m_next) - { - if (p->m_body == 0) - return false; - } - return true; -} - -void handle::destroy() -{ - // Recurse down the chain releasing from tail to head - if (m_next != 0) - m_next->destroy(); - - // Our body knows how to destroy us. If we never got a body, - // there's nothing to do. - if (m_body) - m_body->destroy_handle(this); -} - -// void handle::dummy::nonnull() {} - -}}} // namespace boost::python::converter diff --git a/src/converter/registry.cpp b/src/converter/registry.cpp index c90d709d..bdfa1c8a 100644 --- a/src/converter/registry.cpp +++ b/src/converter/registry.cpp @@ -4,6 +4,7 @@ // "as is" without express or implied warranty, and with no claim as // to its suitability for any purpose. #include +#include #include #include #include @@ -19,20 +20,23 @@ namespace // // The unique to_python converter for the associated C++ type. to_python_value_function m_to_python_converter; - + // The collection of from_python converters for the associated // C++ type. - from_python_converter_base* m_from_python_converters; + lvalue_from_python_registration* m_lvalue_from_python; + rvalue_from_python_registration* m_rvalue_from_python; // The class object associated with this type PyTypeObject* m_class_object; }; - typedef std::map registry_t; + typedef std::map registry_t; registry_t& entries() { static registry_t registry; + +#ifdef BOOST_PYTHON_DYNAMIC_LIB // this conditional should go away eventually. static bool builtin_converters_initialized = false; if (!builtin_converters_initialized) { @@ -42,17 +46,19 @@ namespace // initialize_builtin_converters(); } +#endif return registry; } - entry* find(type_id_t type) + entry* find(undecorated_type_id_t type) { return &entries()[type]; } entry::entry() : m_to_python_converter(0) - , m_from_python_converters(0) + , m_lvalue_from_python(0) + , m_rvalue_from_python(0) , m_class_object(0) { } @@ -78,15 +84,46 @@ namespace registry slot = f; } - from_python_converter_base*& from_python_chain(type_id_t key) + // Insert an lvalue from_python converter + void insert(void* (*convert)(PyObject*), undecorated_type_id_t key) { - return find(key)->m_from_python_converters; + entry* found = find(key); + lvalue_from_python_registration *registration = new lvalue_from_python_registration; + registration->convert = convert; + registration->next = found->m_lvalue_from_python; + found->m_lvalue_from_python = registration; + + insert(convert, 0, key); } - + + // Insert an rvalue from_python converter + void insert(void* (*convertible)(PyObject*) + , constructor_function construct + , undecorated_type_id_t key) + { + entry* found = find(key); + rvalue_from_python_registration *registration = new rvalue_from_python_registration; + registration->convertible = convertible; + registration->construct = construct; + registration->next = found->m_rvalue_from_python; + found->m_rvalue_from_python = registration; + } + PyTypeObject*& class_object(undecorated_type_id_t key) { return find(key)->m_class_object; } + + lvalue_from_python_registration*& lvalue_converters(undecorated_type_id_t key) + { + return find(key)->m_lvalue_from_python; + } + + rvalue_from_python_registration*& rvalue_converters(undecorated_type_id_t key) + { + return find(key)->m_rvalue_from_python; + } + } // namespace registry }}} // namespace boost::python::converter diff --git a/src/converter/unwrap.cpp b/src/converter/unwrap.cpp deleted file mode 100644 index 6a72ab77..00000000 --- a/src/converter/unwrap.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright David Abrahams 2001. Permission to copy, use, -// modify, sell and distribute this software is granted provided this -// copyright notice appears in all copies. This software is provided -// "as is" without express or implied warranty, and with no claim as -// to its suitability for any purpose. - -#include - -namespace boost { namespace python { namespace converter { - -namespace -{ - struct pyobject_unwrapper : unwrapper_base - { - pyobject_unwrapper(); - void* can_convert(PyObject*) const; - }; - - pyobject_unwrapper static_unwrapper; - std::pair unwrapper_pair(&static_unwrapper,&static_unwrapper); - - pyobject_unwrapper::pyobject_unwrapper() - : unwrapper_base(type_id()) - { - } - - void* pyobject_unwrapper::can_convert(PyObject*) const - { - return non_null; - } -} - -BOOST_PYTHON_DECL std::pair& -unwrap_more_::m_unwrapper = unwrapper_pair; - -}}} // namespace boost::python::converter diff --git a/src/converter/unwrapper.cpp b/src/converter/unwrapper.cpp deleted file mode 100644 index 6279febf..00000000 --- a/src/converter/unwrapper.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright David Abrahams 2001. Permission to copy, use, -// modify, sell and distribute this software is granted provided this -// copyright notice appears in all copies. This software is provided -// "as is" without express or implied warranty, and with no claim as -// to its suitability for any purpose. -#include -#include -#include - -namespace boost { namespace python { namespace converter { - -unwrapper_base::unwrapper_base(type_id_t key) - : body(key) -{ - registry::insert(*this); -} - -unwrapper_base::~unwrapper_base() -{ - if (can_unregister()) - registry::remove(*this); -} - -namespace -{ - int arbitrary; -} - -void* const unwrapper_base::non_null = &arbitrary; - -}}} // namespace boost::python::converter diff --git a/src/converter/wrapper.cpp b/src/converter/wrapper.cpp deleted file mode 100644 index 567ff99d..00000000 --- a/src/converter/wrapper.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright David Abrahams 2001. Permission to copy, use, -// modify, sell and distribute this software is granted provided this -// copyright notice appears in all copies. This software is provided -// "as is" without express or implied warranty, and with no claim as -// to its suitability for any purpose. - -#include -#include - -namespace boost { namespace python { namespace converter { - -wrapper_base::wrapper_base(type_id_t type) - : body(type) -{ - registry::insert(*this); -} - -wrapper_base::~wrapper_base() -{ - if (can_unregister()) - registry::remove(*this); -} - -namespace -{ - // This doesn't actually get called, but we need something to fill - // in the slot in the wrap class. - struct identity_wrapper_t : wrapper - { - PyObject* convert(PyObject* source) const - { - return source; - } - }; - - identity_wrapper_t identity_wrapper_object; -} - -BOOST_PYTHON_DECL body& identity_wrapper = identity_wrapper_object; - -}}} // namespace boost::python::converter diff --git a/src/object/class.cpp b/src/object/class.cpp index d35a7b5e..8186f9be 100644 --- a/src/object/class.cpp +++ b/src/object/class.cpp @@ -163,7 +163,7 @@ void instance_holder::install(PyObject* self) throw() } BOOST_PYTHON_DECL void* -find_instance_impl(PyObject* inst, converter::type_id_t type) +find_instance_impl(PyObject* inst, converter::undecorated_type_id_t type) { if (inst->ob_type->ob_type != &class_metatype_object) return 0; diff --git a/test/destroy_test.cpp b/test/destroy_test.cpp new file mode 100644 index 00000000..c6be42fc --- /dev/null +++ b/test/destroy_test.cpp @@ -0,0 +1,81 @@ +#include +#include + +struct bar; + +namespace boost +{ + // lie to the library about bar so we can show that it's destructor is optimized away. + template <> + struct has_trivial_destructor + { + BOOST_STATIC_CONSTANT(bool, value=true); + }; +} + + +int count; +int marks[] = { + -1 + , -1, -1 + , -1, -1, -1, -1 + , -1 +}; +int* kills = marks; + +struct foo +{ + foo() : n(count++) {} + ~foo() + { + *kills++ = n; + } + int n; +}; + +struct bar : foo {}; + +void assert_destructions(int n) +{ + for (int i = 0; i < n; ++i) + assert(marks[i] == i); + assert(marks[n] == -1); +} + +int main() +{ + assert_destructions(0); + typedef int a[2]; + + foo* f1 = new foo; + boost::python::detail::destroy_reference(f1); + assert_destructions(1); + + foo* f2 = new foo[2]; + typedef foo x[2]; + + boost::python::detail::destroy_reference(f2); + assert_destructions(3); + + typedef foo y[2][2]; + x* f3 = new y; + boost::python::detail::destroy_reference(f3); + assert_destructions(7); + + bar* b1 = new bar; + boost::python::detail::destroy_reference(b1); + assert_destructions(7); + + bar* b2 = new bar[2]; + typedef bar xb[2]; + + boost::python::detail::destroy_reference(b2); + assert_destructions(7); + + typedef bar yb[2][2]; + xb* b3 = new yb; + boost::python::detail::destroy_reference(b3); + assert_destructions(7); + + return 0; +} diff --git a/test/indirect_traits_test.cpp b/test/indirect_traits_test.cpp new file mode 100644 index 00000000..a15e7f85 --- /dev/null +++ b/test/indirect_traits_test.cpp @@ -0,0 +1,48 @@ +//#include +#include +#include + +//#define print(expr) printf("%s ==> %s\n", #expr, expr) + +int main() +{ +using namespace boost::python::detail; + + assert(is_reference_to_pointer::value); + assert(is_reference_to_pointer::value); + assert(is_reference_to_pointer::value); + assert(is_reference_to_pointer::value); + + assert(!is_reference_to_pointer::value); + assert(!is_reference_to_pointer::value); + assert(!is_reference_to_pointer::value); + + assert(!is_reference_to_const::value); + assert(is_reference_to_const::value); + assert(!is_reference_to_const::value); + assert(is_reference_to_const::value); + + assert(!is_reference_to_const::value); + assert(!is_reference_to_const::value); + assert(!is_reference_to_const::value); + + assert(is_reference_to_non_const::value); + assert(!is_reference_to_non_const::value); + assert(is_reference_to_non_const::value); + assert(!is_reference_to_non_const::value); + + assert(!is_reference_to_non_const::value); + assert(!is_reference_to_non_const::value); + assert(!is_reference_to_non_const::value); + + assert(!is_reference_to_volatile::value); + assert(!is_reference_to_volatile::value); + assert(is_reference_to_volatile::value); + assert(is_reference_to_volatile::value); + + assert(!is_reference_to_volatile::value); + assert(!is_reference_to_volatile::value); + assert(!is_reference_to_volatile::value); + + return 0; +} diff --git a/test/m1.cpp b/test/m1.cpp index 723b471d..439d58e2 100644 --- a/test/m1.cpp +++ b/test/m1.cpp @@ -9,15 +9,13 @@ #include "complicated.hpp" #include #include +#include #include #include #include #include #include -#include -#include #include -#include #include #include #include @@ -105,7 +103,6 @@ PyObject* new_simple() // description of how the type parameters to wrapper<> and unwrapper<> // are selected. // -using boost::python::converter::from_python_data; using boost::python::to_python_converter; // Wrap a simple by copying it into a Simple @@ -120,16 +117,13 @@ struct simple_to_python } }; -int noddy_to_int(PyObject* p, from_python_data&) +struct int_from_noddy_extractor { - return static_cast(p)->x; -} - -// Extract a mutable reference to an int from a Noddy. -int& noddy_to_int_ref(PyObject* p, from_python_data&) -{ - return static_cast(p)->x; -} + static int& execute(NoddyObject& p) + { + return p.x; + } +}; // // Some C++ functions to expose to Python @@ -205,40 +199,23 @@ D take_d(D const& d) { return d; } BOOST_PYTHON_MODULE_INIT(m1) { - using boost::python::module; - using boost::python::class_; - using boost::python::converter::from_python_converter; - using boost::python::lvalue_from_python; - using boost::python::value_from_python; - using boost::python::type_from_python; - using boost::python::get_member; - using boost::python::copy_const_reference; - using boost::python::return_value_policy; + using namespace boost::python; using boost::mpl::type_list; - // Create the converters; they are self-registering/unregistering. - static simple_to_python c1; + simple_to_python(); - static from_python_converter c2( - &(boost::python::type_from_python<&NoddyType>::convertible), noddy_to_int); - - static from_python_converter c3( - &(boost::python::type_from_python<&NoddyType>::convertible), noddy_to_int_ref); + type_from_python<&NoddyType,int_from_noddy_extractor>(); - static boost::python::lvalue_from_python< + boost::python::type_from_python< &SimpleType - , simple - , SimpleObject #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 - , boost::python::get_member + , member_extractor #else , extract_simple_object #endif - > - unwrap_simple; + >(); - static boost::python::lvalue_from_python<&SimpleType, SimpleObject> - unwrap_simple2; + type_from_python<&SimpleType, identity_extractor >(); module m1("m1"); diff --git a/test/pointer_type_id_test.cpp b/test/pointer_type_id_test.cpp new file mode 100644 index 00000000..24035709 --- /dev/null +++ b/test/pointer_type_id_test.cpp @@ -0,0 +1,39 @@ +#include +#include +#include + +int main() +{ + using namespace boost::python::converter; + + undecorated_type_id_t x + = undecorated_type_id(); + + + assert(pointer_type_id() == x); + assert(pointer_type_id() == x); + assert(pointer_type_id() == x); + assert(pointer_type_id() == x); + + assert(pointer_type_id() == x); + assert(pointer_type_id() == x); + assert(pointer_type_id() == x); + assert(pointer_type_id() == x); + + assert(pointer_type_id() == x); + assert(pointer_type_id() == x); + assert(pointer_type_id() == x); + assert(pointer_type_id() == x); + + assert(pointer_type_id() == x); + assert(pointer_type_id() == x); + assert(pointer_type_id() == x); + assert(pointer_type_id() == x); + + assert(pointer_type_id() == x); + assert(pointer_type_id() == x); + assert(pointer_type_id() == x); + assert(pointer_type_id() == x); + + return 0; +}