2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-19 16:32:16 +00:00

New-style polymorphism

[SVN r24083]
This commit is contained in:
Dave Abrahams
2004-07-26 15:34:36 +00:00
parent 597342bf15
commit c8e8ccfa22
24 changed files with 957 additions and 294 deletions

View File

@@ -53,6 +53,7 @@ if [ check-python-config ]
object/iterator.cpp
object_protocol.cpp
object_operators.cpp
wrapper.cpp
;
dll boost_python

View File

@@ -32,6 +32,12 @@ struct base_type_traits<PyTypeObject>
typedef PyObject type;
};
template <>
struct base_type_traits<PyMethodObject>
{
typedef PyObject type;
};
}} // namespace boost::python
#endif // BASE_TYPE_TRAITS_DWA2002614_HPP

View File

@@ -29,6 +29,8 @@
# include <boost/python/detail/operator_id.hpp>
# include <boost/python/detail/def_helper.hpp>
# include <boost/python/detail/force_instantiate.hpp>
# include <boost/python/detail/unwrap_type_id.hpp>
# include <boost/python/detail/unwrap_wrapper.hpp>
# include <boost/type_traits/is_same.hpp>
# include <boost/type_traits/is_member_function_pointer.hpp>
@@ -151,7 +153,7 @@ namespace detail
// This is the primary mechanism through which users will expose
// C++ classes to Python.
template <
class T // class being wrapped
class W // class being wrapped
, class X1 // = detail::not_specified
, class X2 // = detail::not_specified
, class X3 // = detail::not_specified
@@ -160,9 +162,9 @@ class class_ : public objects::class_base
{
public: // types
typedef objects::class_base base;
typedef class_<T,X1,X2,X3> self;
typedef typename objects::class_metadata<T,X1,X2,X3> metadata;
typedef T wrapped_type;
typedef class_<W,X1,X2,X3> self;
typedef typename objects::class_metadata<W,X1,X2,X3> metadata;
typedef W wrapped_type;
private: // types
@@ -175,7 +177,7 @@ class class_ : public objects::class_base
id_vector()
{
// Stick the derived class id into the first element of the array
ids[0] = type_id<T>();
ids[0] = detail::unwrap_type_id((W*)0, (W*)0);
// Write the rest of the elements into succeeding positions.
type_info* p = ids + 1;
@@ -231,7 +233,9 @@ class class_ : public objects::class_base
template <class F>
self& def(char const* name, F f)
{
this->def_impl(name, f, detail::def_helper<char const*>(0), &f);
this->def_impl(
detail::unwrap_wrapper((W*)0)
, name, f, detail::def_helper<char const*>(0), &f);
return *this;
}
@@ -250,9 +254,10 @@ class class_ : public objects::class_base
// def(name, function, doc_string, policy)
this->def_impl(
name, fn
, detail::def_helper<A1,A2>(a1,a2)
, &fn);
detail::unwrap_wrapper((W*)0)
, name, fn
, detail::def_helper<A1,A2>(a1,a2)
, &fn);
return *this;
}
@@ -261,9 +266,10 @@ class class_ : public objects::class_base
self& def(char const* name, Fn fn, A1 const& a1, A2 const& a2, A3 const& a3)
{
this->def_impl(
name, fn
, detail::def_helper<A1,A2,A3>(a1,a2,a3)
, &fn);
detail::unwrap_wrapper((W*)0)
, name, fn
, detail::def_helper<A1,A2,A3>(a1,a2,a3)
, &fn);
return *this;
}
@@ -371,7 +377,8 @@ class class_ : public objects::class_base
typedef typename api::is_object_operators<F>::type is_obj_or_proxy;
return this->make_fn_impl(
f, is_obj_or_proxy(), (char*)0, detail::is_data_member_pointer<F>()
detail::unwrap_wrapper((W*)0)
, f, is_obj_or_proxy(), (char*)0, detail::is_data_member_pointer<F>()
);
}
@@ -381,32 +388,33 @@ class class_ : public objects::class_base
typedef typename api::is_object_operators<F>::type is_obj_or_proxy;
return this->make_fn_impl(
f, is_obj_or_proxy(), (int*)0, detail::is_data_member_pointer<F>()
detail::unwrap_wrapper((W*)0)
, f, is_obj_or_proxy(), (int*)0, detail::is_data_member_pointer<F>()
);
}
template <class F>
object make_fn_impl(F const& f, mpl::false_, void*, mpl::false_)
template <class T, class F>
object make_fn_impl(T*, F const& f, mpl::false_, void*, mpl::false_)
{
return python::make_function(f, default_call_policies(), detail::get_signature(f, (T*)0));
}
template <class D, class B>
object make_fn_impl(D B::*pm_, mpl::false_, char*, mpl::true_)
template <class T, class D, class B>
object make_fn_impl(T*, D B::*pm_, mpl::false_, char*, mpl::true_)
{
D T::*pm = pm_;
return python::make_getter(pm);
}
template <class D, class B>
object make_fn_impl(D B::*pm_, mpl::false_, int*, mpl::true_)
template <class T, class D, class B>
object make_fn_impl(T*, D B::*pm_, mpl::false_, int*, mpl::true_)
{
D T::*pm = pm_;
return python::make_setter(pm);
}
template <class F>
object make_fn_impl(F const& x, mpl::true_, void*, mpl::false_)
template <class T, class F>
object make_fn_impl(T*, F const& x, mpl::true_, void*, mpl::false_)
{
return x;
}
@@ -462,9 +470,10 @@ class class_ : public objects::class_base
// generic visitor and everything else.
//
// @group def_impl {
template <class Helper, class LeafVisitor, class Visitor>
template <class T, class Helper, class LeafVisitor, class Visitor>
inline void def_impl(
char const* name
T*
, char const* name
, LeafVisitor
, Helper const& helper
, def_visitor<Visitor> const* v
@@ -473,9 +482,10 @@ class class_ : public objects::class_base
v->visit(*this, name, helper);
}
template <class Fn, class Helper>
template <class T, class Fn, class Helper>
inline void def_impl(
char const* name
T*
, char const* name
, Fn fn
, Helper const& helper
, ...
@@ -510,7 +520,7 @@ class class_ : public objects::class_base
, Helper const& helper
, mpl::bool_<true>)
{
detail::error::virtual_function_default<T,Fn>::must_be_derived_class_member(
detail::error::virtual_function_default<W,Fn>::must_be_derived_class_member(
helper.default_implementation());
objects::add_to_namespace(
@@ -554,7 +564,8 @@ class class_ : public objects::class_base
, ...)
{
this->def_impl(
name
detail::unwrap_wrapper((W*)0)
, name
, fn
, detail::def_helper<A1>(a1)
, &fn
@@ -569,23 +580,23 @@ class class_ : public objects::class_base
// implementations
//
template <class T, class X1, class X2, class X3>
inline class_<T,X1,X2,X3>::class_(char const* name, char const* doc)
template <class W, class X1, class X2, class X3>
inline class_<W,X1,X2,X3>::class_(char const* name, char const* doc)
: base(name, id_vector::size, id_vector().ids, doc)
{
this->initialize(init<>());
// select_holder::assert_default_constructible();
}
template <class T, class X1, class X2, class X3>
inline class_<T,X1,X2,X3>::class_(char const* name, no_init_t)
template <class W, class X1, class X2, class X3>
inline class_<W,X1,X2,X3>::class_(char const* name, no_init_t)
: base(name, id_vector::size, id_vector().ids)
{
this->initialize(no_init);
}
template <class T, class X1, class X2, class X3>
inline class_<T,X1,X2,X3>::class_(char const* name, char const* doc, no_init_t)
template <class W, class X1, class X2, class X3>
inline class_<W,X1,X2,X3>::class_(char const* name, char const* doc, no_init_t)
: base(name, id_vector::size, id_vector().ids, doc)
{
this->initialize(no_init);

View File

@@ -9,9 +9,11 @@
# include <boost/python/converter/rvalue_from_python_data.hpp>
# include <boost/python/converter/registered.hpp>
# include <boost/python/converter/registered_pointee.hpp>
# include <boost/python/converter/object_manager.hpp>
# include <boost/python/detail/void_ptr.hpp>
# include <boost/python/detail/void_return.hpp>
# include <boost/python/errors.hpp>
# include <boost/python/handle.hpp>
# include <boost/type_traits/has_trivial_copy.hpp>
# include <boost/mpl/and.hpp>
# include <boost/mpl/bool.hpp>

View File

@@ -0,0 +1,70 @@
// Copyright David Abrahams 2004. 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)
#ifndef ENABLE_IF_DWA2004722_HPP
# define ENABLE_IF_DWA2004722_HPP
# include <boost/python/detail/sfinae.hpp>
# include <boost/detail/workaround.hpp>
# if BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
# include <boost/mpl/if.hpp>
namespace boost { namespace python { namespace detail {
template <class C, class T = int>
struct enable_if_arg
{
typedef typename mpl::if_<C,T,int&>::type type;
};
template <class C, class T = int>
struct disable_if_arg
{
typedef typename mpl::if_<C,int&,T>::type type;
};
template <class C, class T>
struct enable_if_ret
{
typedef typename mpl::if_<C,T,int[2]>::type type;
};
template <class C, class T>
struct disable_if_ret
{
typedef typename mpl::if_<C,int[2],T>::type type;
};
}}} // namespace boost::python::detail
# elif !defined(BOOST_NO_SFINAE)
# include <boost/utility/enable_if.hpp>
namespace boost { namespace python { namespace detail {
template <class C, class T>
struct enable_if_arg
: enable_if<C,T>
{};
template <class C, class T>
struct disable_if_arg
: disable_if<C,T>
{};
template <class C, class T>
struct enable_if_ret
: enable_if<C,T>
{};
template <class C, class T>
struct disable_if_ret
: disable_if<C,T>
{};
}}} // namespace boost::python::detail
# endif
#endif // ENABLE_IF_DWA2004722_HPP

View File

@@ -0,0 +1,29 @@
// Copyright David Abrahams 2004. 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)
#ifndef IS_WRAPPER_DWA2004723_HPP
# define IS_WRAPPER_DWA2004723_HPP
# include <boost/python/detail/prefix.hpp>
# include <boost/mpl/bool.hpp>
namespace boost { namespace python {
template <class T> class wrapper;
namespace detail
{
typedef char (&is_not_wrapper)[2];
is_not_wrapper is_wrapper_helper(...);
template <class T>
char is_wrapper_helper(wrapper<T> const volatile*);
// A metafunction returning true iff T is [derived from] wrapper<U>
template <class T>
struct is_wrapper
: mpl::bool_<(sizeof(detail::is_wrapper_helper((T*)0)) == 1)>
{};
}}} // namespace boost::python::detail
#endif // IS_WRAPPER_DWA2004723_HPP

View File

@@ -0,0 +1,13 @@
// Copyright David Abrahams 2004. 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)
#ifndef SFINAE_DWA2004723_HPP
# define SFINAE_DWA2004723_HPP
# include <boost/python/detail/prefix.hpp>
# if defined(BOOST_NO_SFINAE) && !defined(BOOST_MSVC)
# define BOOST_PYTHON_NO_SFINAE
# endif
#endif // SFINAE_DWA2004723_HPP

View File

@@ -1,150 +0,0 @@
// 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)
#ifndef UNWIND_TYPE_DWA200222_HPP
# define UNWIND_TYPE_DWA200222_HPP
# include <boost/python/detail/cv_category.hpp>
# include <boost/python/detail/indirect_traits.hpp>
# include <boost/type_traits/object_traits.hpp>
namespace boost { namespace python { namespace detail {
template <class Generator, class U>
inline typename Generator::result_type
unwind_type_cv(U* p, cv_unqualified, Generator* = 0)
{
return Generator::execute(p);
}
template <class Generator, class U>
inline typename Generator::result_type
unwind_type_cv(U const* p, const_, Generator* = 0)
{
return unwind_type(const_cast<U*>(p), (Generator*)0);
}
template <class Generator, class U>
inline typename Generator::result_type
unwind_type_cv(U volatile* p, volatile_, Generator* = 0)
{
return unwind_type(const_cast<U*>(p), (Generator*)0);
}
template <class Generator, class U>
inline typename Generator::result_type
unwind_type_cv(U const volatile* p, const_volatile_, Generator* = 0)
{
return unwind_type(const_cast<U*>(p), (Generator*)0);
}
template <class Generator, class U>
inline typename Generator::result_type
unwind_ptr_type(U* p, Generator* = 0)
{
typedef typename cv_category<U>::type tag;
return unwind_type_cv<Generator>(p, tag());
}
template <bool is_ptr>
struct unwind_helper
{
template <class Generator, class U>
static typename Generator::result_type
execute(U p, Generator* = 0)
{
return unwind_ptr_type(p, (Generator*)0);
}
};
template <>
struct unwind_helper<false>
{
template <class Generator, class U>
static typename Generator::result_type
execute(U& p, Generator* = 0)
{
return unwind_ptr_type(&p, (Generator*)0);
}
};
template <class Generator, class U>
inline typename Generator::result_type
unwind_type(U const& p, Generator* = 0)
{
return unwind_helper<is_pointer<U>::value>::execute(p, (Generator*)0);
}
enum { direct_ = 0, pointer_ = 1, reference_ = 2, reference_to_pointer_ = 3 };
template <int indirection> struct unwind_helper2;
template <>
struct unwind_helper2<direct_>
{
template <class Generator, class U>
static typename Generator::result_type
execute(U(*)(), Generator* = 0)
{
return unwind_ptr_type((U*)0, (Generator*)0);
}
};
template <>
struct unwind_helper2<pointer_>
{
template <class Generator, class U>
static typename Generator::result_type
execute(U*(*)(), Generator* = 0)
{
return unwind_ptr_type((U*)0, (Generator*)0);
}
};
template <>
struct unwind_helper2<reference_>
{
template <class Generator, class U>
static typename Generator::result_type
execute(U&(*)(), Generator* = 0)
{
return unwind_ptr_type((U*)0, (Generator*)0);
}
};
template <>
struct unwind_helper2<reference_to_pointer_>
{
template <class Generator, class U>
static typename Generator::result_type
execute(U&(*)(), Generator* = 0)
{
return unwind_ptr_type(U(0), (Generator*)0);
}
};
// Call this one with both template parameters explicitly specified
// and no function arguments:
//
// return unwind_type<my_generator,T>();
//
// Doesn't work if T is an array type; we could handle that case, but
// why bother?
template <class Generator, class U>
inline typename Generator::result_type
unwind_type(boost::type<U>*p = 0, Generator* = 0)
{
BOOST_STATIC_CONSTANT(int, indirection
= (is_pointer<U>::value ? pointer_ : 0)
+ (is_reference_to_pointer<U>::value
? reference_to_pointer_
: is_reference<U>::value
? reference_
: 0));
return unwind_helper2<indirection>::execute((U(*)())0,(Generator*)0);
}
}}} // namespace boost::python::detail
#endif // UNWIND_TYPE_DWA200222_HPP

View File

@@ -0,0 +1,31 @@
// Copyright David Abrahams 2004. 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)
#ifndef UNWRAP_TYPE_ID_DWA2004722_HPP
# define UNWRAP_TYPE_ID_DWA2004722_HPP
# include <boost/python/type_id.hpp>
# include <boost/mpl/bool.hpp>
namespace boost { namespace python {
template <class T> class wrapper;
namespace detail {
template <class T>
inline type_info unwrap_type_id(T*, ...)
{
return type_id<T>();
}
template <class U, class T>
inline type_info unwrap_type_id(U*, wrapper<T>*)
{
return type_id<T>();
}
}}} // namespace boost::python::detail
#endif // UNWRAP_TYPE_ID_DWA2004722_HPP

View File

@@ -0,0 +1,48 @@
// Copyright David Abrahams 2004. 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)
#ifndef UNWRAP_WRAPPER_DWA2004723_HPP
# define UNWRAP_WRAPPER_DWA2004723_HPP
# include <boost/python/detail/prefix.hpp>
# include <boost/python/detail/is_wrapper.hpp>
# if defined(BOOST_PYTHON_NO_SFINAE)
# include <boost/mpl/apply_if.hpp>
# include <boost/mpl/identity.hpp>
# else
# include <boost/python/detail/enable_if.hpp>
# endif
namespace boost { namespace python { namespace detail {
# if defined(BOOST_PYTHON_NO_SFINAE)
template <class T>
struct unwrap_wrapper_helper
{
typedef typename T::_wrapper_wrapped_type_ type;
};
template <class T>
typename mpl::apply_if<is_wrapper<T>,unwrap_wrapper_helper<T>,mpl::identity<T> >::type*
unwrap_wrapper(T*)
{
return 0;
}
# else
template <class T>
typename disable_if_ret<is_wrapper<T>,T*>::type
unwrap_wrapper(T*)
{
return 0;
}
template <class T>
T* unwrap_wrapper(wrapper<T>*)
{
return 0;
}
# endif
}}} // namespace boost::python::detail
#endif // UNWRAP_WRAPPER_DWA2004723_HPP

View File

@@ -0,0 +1,86 @@
// Copyright David Abrahams 2004. 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)
#ifndef WRAPPER_BASE_DWA2004722_HPP
# define WRAPPER_BASE_DWA2004722_HPP
# include <boost/python/detail/prefix.hpp>
# include <boost/type_traits/is_polymorphic.hpp>
# include <boost/mpl/bool.hpp>
namespace boost { namespace python {
class override;
namespace detail
{
class BOOST_PYTHON_DECL wrapper_base;
namespace wrapper_base_ // ADL disabler
{
inline PyObject* get_owner(wrapper_base const volatile& w);
inline PyObject*
owner_impl(void const volatile* x, mpl::false_)
{
return 0;
}
template <class T>
inline PyObject*
owner_impl(T const volatile* x, mpl::true_)
{
if (wrapper_base const volatile* w = dynamic_cast<wrapper_base const volatile*>(x))
{
return wrapper_base_::get_owner(*w);
}
return 0;
}
template <class T>
inline PyObject*
owner(T const volatile* x)
{
return wrapper_base_::owner_impl(x,is_polymorphic<T>());
}
}
class BOOST_PYTHON_DECL wrapper_base
{
friend void initialize_wrapper(PyObject* self, wrapper_base* w);
friend PyObject* wrapper_base_::get_owner(wrapper_base const volatile& w);
protected:
wrapper_base() : m_self(0) {}
override get_override(
char const* name, PyTypeObject* class_object) const;
private:
void detach();
private:
PyObject* m_self;
};
namespace wrapper_base_ // ADL disabler
{
inline PyObject* get_owner(wrapper_base const volatile& w)
{
return w.m_self;
}
}
inline void initialize_wrapper(PyObject* self, wrapper_base* w)
{
w->m_self = self;
}
inline void initialize_wrapper(PyObject* self, ...) {}
} // namespace detail
}} // namespace boost::python
#endif // WRAPPER_BASE_DWA2004722_HPP

View File

@@ -12,16 +12,23 @@
# include <boost/python/converter/rvalue_from_python_data.hpp>
# include <boost/python/converter/registered.hpp>
# include <boost/python/converter/registered_pointee.hpp>
# include <boost/call_traits.hpp>
# include <boost/python/object_core.hpp>
# include <boost/python/refcount.hpp>
# include <boost/utility.hpp>
# include <boost/python/detail/copy_ctor_mutates_rhs.hpp>
# include <boost/python/detail/void_ptr.hpp>
# include <boost/python/detail/void_return.hpp>
# include <boost/utility.hpp>
# include <boost/call_traits.hpp>
namespace boost { namespace python {
namespace api
{
class object;
}
namespace converter
{
template <class Ptr>
@@ -125,7 +132,7 @@ struct extract
}
extract(PyObject*);
extract(object const&);
extract(api::object const&);
};
//
@@ -138,7 +145,7 @@ inline extract<T>::extract(PyObject* o)
}
template <class T>
inline extract<T>::extract(object const& o)
inline extract<T>::extract(api::object const& o)
: base(o.ptr())
{
}

View File

@@ -75,7 +75,7 @@ struct register_base_of
// need some registration of their own.
//
template <class T, class Bases>
void register_shared_ptr_from_python_and_casts(T*, Bases)
inline void register_shared_ptr_from_python_and_casts(T*, Bases)
{
// Constructor performs registration
python::detail::force_instantiate(converter::shared_ptr_from_python<T>());
@@ -166,16 +166,13 @@ struct class_metadata
use_value_holder
, mpl::identity<held_type>
, pointee<held_type>
>::type wrapper;
>::type wrapped;
// Determine whether wrapper needs to be separately registered
typedef is_base_and_derived<T,wrapper> use_callback_class;
// Determine whether to use a holder with a back-reference
// Determine whether to use a "back-reference holder"
typedef mpl::or_<
use_callback_class
, has_back_reference<T>
has_back_reference<T>
, is_same<held_type_arg,T>
, is_base_and_derived<T,wrapped>
> use_back_reference;
// Select the holder.
@@ -183,7 +180,7 @@ struct class_metadata
use_back_reference
, mpl::if_<
use_value_holder
, value_holder_back_reference<T, wrapper>
, value_holder_back_reference<T, wrapped>
, pointer_holder_back_reference<held_type,T>
>
, mpl::if_<
@@ -195,52 +192,75 @@ struct class_metadata
inline static void register_() // Register the runtime metadata.
{
objects::register_shared_ptr_from_python_and_casts((T*)0, bases());
class_metadata::maybe_register_callback_class(use_callback_class());
class_metadata::maybe_register_class_to_python(is_noncopyable());
class_metadata::maybe_register_pointer_to_python(
(use_value_holder*)0, (use_back_reference*)0);
class_metadata::register_aux((T*)0);
}
private:
template <class T2>
inline static void register_aux(python::wrapper<T2>*)
{
class_metadata::register_aux2((T2*)0, mpl::true_());
}
inline static void register_aux(void*)
{
typedef typename is_base_and_derived<T,wrapped>::type use_callback;
class_metadata::register_aux2((T*)0, use_callback());
}
template <class T2, class Callback>
inline static void register_aux2(T2*, Callback)
{
objects::register_shared_ptr_from_python_and_casts((T2*)0, bases());
class_metadata::maybe_register_callback_class((T2*)0, Callback());
class_metadata::maybe_register_class_to_python((T2*)0, is_noncopyable());
class_metadata::maybe_register_pointer_to_python(
(T2*)0, (use_value_holder*)0, (use_back_reference*)0);
}
//
// Support for converting smart pointers to python
//
inline static void maybe_register_pointer_to_python(void*,void*) {}
inline static void maybe_register_pointer_to_python(mpl::false_*, mpl::false_*)
inline static void maybe_register_pointer_to_python(void*,void*,void*) {}
template <class T2>
inline static void maybe_register_pointer_to_python(T2*, mpl::false_*, mpl::false_*)
{
python::detail::force_instantiate(
objects::class_value_wrapper<
held_type
, make_ptr_instance<T, pointer_holder<held_type, T> >
, make_ptr_instance<T2, pointer_holder<held_type, T2> >
>()
);
}
//
// Support for registering to-python converters
//
inline static void maybe_register_class_to_python(mpl::true_) {}
inline static void maybe_register_class_to_python(mpl::false_)
inline static void maybe_register_class_to_python(void*, mpl::true_) {}
template <class T2>
inline static void maybe_register_class_to_python(T2*, mpl::false_)
{
python::detail::force_instantiate(class_cref_wrapper<T, make_instance<T, holder> >());
python::detail::force_instantiate(class_cref_wrapper<T2, make_instance<T2, holder> >());
}
//
// Support for registering callback classes
//
inline static void maybe_register_callback_class(mpl::false_) {}
inline static void maybe_register_callback_class(void*, mpl::false_) {}
inline static void maybe_register_callback_class(mpl::true_)
template <class T2>
inline static void maybe_register_callback_class(T2*, mpl::true_)
{
objects::register_shared_ptr_from_python_and_casts(
(wrapper*)0, mpl::single_view<T>());
(wrapped*)0, mpl::single_view<T2>());
// explicit qualification of type_id makes msvc6 happy
objects::copy_class_object(python::type_id<T>(), python::type_id<wrapper>());
objects::copy_class_object(python::type_id<T2>(), python::type_id<wrapped>());
}
};

View File

@@ -12,13 +12,17 @@
# include <boost/type.hpp>
# include <boost/python/instance_holder.hpp>
# include <boost/python/type_id.hpp>
# include <boost/python/object/inheritance_query.hpp>
# include <boost/python/object/forward.hpp>
# include <boost/python/pointee.hpp>
# include <boost/python/type_id.hpp>
# include <boost/python/detail/wrapper_base.hpp>
# include <boost/python/detail/force_instantiate.hpp>
# include <boost/python/detail/preprocessor.hpp>
# include <boost/mpl/if.hpp>
# include <boost/mpl/apply.hpp>
@@ -31,6 +35,13 @@
# include <boost/detail/workaround.hpp>
namespace boost { namespace python {
template <class T> class wrapper;
}}
namespace boost { namespace python { namespace objects {
# if BOOST_WORKAROUND(__GNUC__, == 2)
@@ -55,6 +66,17 @@ struct pointer_holder : instance_holder
private: // required holder implementation
void* holds(type_info);
template <class T>
inline void* holds_wrapped(type_info dst_t, wrapper<T>*,T* p)
{
return python::type_id<T>() == dst_t ? p : 0;
}
inline void* holds_wrapped(type_info, ...)
{
return 0;
}
private: // data members
Pointer m_p;
@@ -107,6 +129,9 @@ void* pointer_holder<Pointer, Value>::holds(type_info dst_t)
if (p == 0)
return 0;
if (void* wrapped = holds_wrapped(dst_t, p, p))
return wrapped;
type_info src_t = python::type_id<Value>();
return src_t == dst_t ? p : find_dynamic_type(p, src_t, dst_t);
}
@@ -145,11 +170,13 @@ void* pointer_holder_back_reference<Pointer, Value>::holds(type_info dst_t)
# if (N != 0)
template< BOOST_PP_ENUM_PARAMS_Z(1, N, class A) >
# endif
pointer_holder(PyObject* BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM_BINARY_PARAMS_Z(1, N, A, a))
pointer_holder(PyObject* self BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM_BINARY_PARAMS_Z(1, N, A, a))
: m_p(new Value(
BOOST_PP_REPEAT_1ST(N, BOOST_PYTHON_UNFORWARD_LOCAL, nil)
))
{}
{
python::detail::initialize_wrapper(self, &*this->m_p);
}
# undef N

View File

@@ -13,6 +13,7 @@
# include <boost/python/instance_holder.hpp>
# include <boost/python/type_id.hpp>
# include <boost/python/wrapper.hpp>
# include <boost/python/object/inheritance_query.hpp>
# include <boost/python/object/forward.hpp>
@@ -49,7 +50,17 @@ struct value_holder : instance_holder
private: // required holder implementation
void* holds(type_info);
template <class T>
inline void* holds_wrapped(type_info dst_t, wrapper<T>*,T* p)
{
return python::type_id<T>() == dst_t ? p : 0;
}
inline void* holds_wrapped(type_info, ...)
{
return 0;
}
private: // data members
Value m_held;
};
@@ -76,6 +87,9 @@ private: // required holder implementation
template <class Value>
void* value_holder<Value>::holds(type_info dst_t)
{
if (void* wrapped = holds_wrapped(dst_t, &m_held, &m_held))
return wrapped;
type_info src_t = python::type_id<Value>();
return src_t == dst_t ? &m_held
: find_static_type(&m_held, src_t, dst_t);
@@ -114,11 +128,13 @@ void* value_holder_back_reference<Value,Held>::holds(
template <BOOST_PP_ENUM_PARAMS_Z(1, N, class A)>
# endif
value_holder(
PyObject* BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM_BINARY_PARAMS_Z(1, N, A, a))
PyObject* self BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM_BINARY_PARAMS_Z(1, N, A, a))
: m_held(
BOOST_PP_REPEAT_1ST(N, BOOST_PYTHON_UNFORWARD_LOCAL, nil)
)
{}
{
python::detail::initialize_wrapper(self, &this->m_held);
}
# undef N

132
include/boost/python/override.hpp Executable file
View File

@@ -0,0 +1,132 @@
#if !defined(BOOST_PP_IS_ITERATING)
// Copyright David Abrahams 2004. 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)
#ifndef OVERRIDE_DWA2004721_HPP
# define OVERRIDE_DWA2004721_HPP
# include <boost/python/detail/prefix.hpp>
# include <boost/python/converter/return_from_python.hpp>
# include <boost/python/extract.hpp>
# include <boost/python/handle.hpp>
# include <boost/preprocessor/iterate.hpp>
# include <boost/preprocessor/repeat.hpp>
# include <boost/preprocessor/debug/line.hpp>
# include <boost/preprocessor/repetition/enum_params.hpp>
# include <boost/preprocessor/repetition/enum_binary_params.hpp>
# include <boost/type.hpp>
namespace boost { namespace python {
class override;
namespace detail
{
class wrapper_base;
// The result of calling a method.
class method_result
{
private:
friend class override;
explicit method_result(PyObject* x)
: m_obj(x)
{}
public:
template <class T>
operator T()
{
converter::return_from_python<T> converter;
return converter(m_obj.release());
}
# if !defined(BOOST_MSVC) || BOOST_WORKAROUND(_MSC_FULL_VER, > 140040607)
template <class T>
operator T&() const
{
converter::return_from_python<T&> converter;
return converter(m_obj.release());
}
# endif
template <class T>
T as(type<T>* = 0)
{
converter::return_from_python<T> converter;
return converter(m_obj.release());
}
template <class T>
T unchecked(type<T>* = 0)
{
return extract<T>(m_obj)();
}
private:
mutable handle<> m_obj;
};
}
class override : public object
{
private:
friend class detail::wrapper_base;
override(handle<> x)
: object(x)
{}
public:
detail::method_result
operator()() const
{
detail::method_result x(
PyEval_CallFunction(
this->ptr()
, const_cast<char*>("()")
));
return x;
}
# define BOOST_PYTHON_fast_arg_to_python_get(z, n, _) \
, converter::arg_to_python<A##n>(a##n).get()
# define BOOST_PP_ITERATION_PARAMS_1 (3, (1, BOOST_PYTHON_MAX_ARITY, <boost/python/override.hpp>))
# include BOOST_PP_ITERATE()
# undef BOOST_PYTHON_fast_arg_to_python_get
};
}} // namespace boost::python
#endif // OVERRIDE_DWA2004721_HPP
#else
# if !(BOOST_WORKAROUND(__MWERKS__, > 0x3100) \
&& BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3201)))
# line BOOST_PP_LINE(__LINE__, override.hpp)
# endif
# define N BOOST_PP_ITERATION()
template <
BOOST_PP_ENUM_PARAMS_Z(1, N, class A)
>
detail::method_result
operator()( BOOST_PP_ENUM_BINARY_PARAMS_Z(1, N, A, const& a) ) const
{
detail::method_result x(
PyEval_CallFunction(
this->ptr()
, const_cast<char*>("(" BOOST_PP_REPEAT_1ST(N, BOOST_PYTHON_FIXED, "O") ")")
BOOST_PP_REPEAT_1ST(N, BOOST_PYTHON_fast_arg_to_python_get, nil)
));
return x;
}
# undef N
#endif

View File

@@ -7,24 +7,58 @@
# include <boost/python/detail/prefix.hpp>
# include <boost/type_traits/object_traits.hpp>
# include <boost/python/object/pointer_holder.hpp>
# include <boost/python/object/instance.hpp>
# include <boost/python/converter/registered.hpp>
# include <boost/python/detail/unwind_type.hpp>
# include <boost/python/detail/none.hpp>
# include <boost/shared_ptr.hpp>
# include <boost/python/object/make_ptr_instance.hpp>
# include <memory>
# include <boost/python/detail/none.hpp>
# include <boost/python/refcount.hpp>
# include <boost/type_traits/is_pointer.hpp>
# include <boost/type_traits/is_polymorphic.hpp>
# include <boost/mpl/bool.hpp>
# if defined(__ICL) && __ICL < 600
# include <boost/shared_ptr.hpp>
# else
# include <memory>
# endif
namespace boost { namespace python {
template <class T, class MakeHolder>
struct to_python_indirect
{
PyObject* operator()(T ptr) const;
template <class U>
inline PyObject*
operator()(U const& ref) const
{
return this->execute(const_cast<U&>(ref), is_pointer<U>());
}
private:
static PyTypeObject* type();
template <class U>
inline PyObject* execute(U* ptr, mpl::true_) const
{
// No special NULL treatment for references
if (ptr == 0)
return python::detail::none();
else
return this->execute(*ptr, mpl::false_());
}
template <class U>
inline PyObject* execute(U const& x, mpl::false_) const
{
U* const p = &const_cast<U&>(x);
if (is_polymorphic<U>::value)
{
if (PyObject* o = detail::wrapper_base_::owner(p))
return incref(o);
}
return MakeHolder::execute(p);
}
};
//
@@ -34,9 +68,8 @@ namespace detail
{
struct make_owning_holder
{
typedef PyObject* result_type;
template <class T>
static result_type execute(T* p)
static PyObject* execute(T* p)
{
// can't use auto_ptr with Intel 5 and VC6 Dinkum library
// for some reason. We get link errors against the auto_ptr
@@ -48,66 +81,21 @@ namespace detail
# endif
typedef objects::pointer_holder<smart_pointer, T> holder_t;
smart_pointer ptr(p);
smart_pointer ptr(const_cast<T*>(p));
return objects::make_ptr_instance<T, holder_t>::execute(ptr);
}
};
struct make_reference_holder
{
typedef PyObject* result_type;
template <class T>
static result_type execute(T* p)
static PyObject* execute(T* p)
{
typedef objects::pointer_holder<T*, T> holder_t;
return objects::make_ptr_instance<T, holder_t>::execute(p);
T* q = const_cast<T*>(p);
return objects::make_ptr_instance<T, holder_t>::execute(q);
}
};
struct get_pointer_class
{
typedef PyTypeObject* result_type;
template <class T>
static result_type execute(T* p)
{
BOOST_STATIC_ASSERT(is_class<T>::value);
return converter::registered<T>::converters.class_object;
}
};
// null_pointer_to_none -- return none() for null pointers and 0 for all other types/values
//
// Uses simulated partial ordering
template <class T>
inline PyObject* null_pointer_to_none(T&, int)
{
return 0;
}
// overload for pointers
template <class T>
inline PyObject* null_pointer_to_none(T* x, long)
{
return x == 0 ? python::detail::none() : 0;
}
}
template <class T, class MakeHolder>
inline PyObject* to_python_indirect<T,MakeHolder>::operator()(T x) const
{
BOOST_STATIC_ASSERT(is_pointer<T>::value || is_reference<T>::value);
PyObject* const null_result = detail::null_pointer_to_none(x, 1L);
if (null_result != 0)
return null_result;
return detail::unwind_type<MakeHolder>(x);
}
template <class T, class MakeHolder>
inline PyTypeObject* to_python_indirect<T,MakeHolder>::type()
{
return detail::unwind_type<detail::get_pointer_class,T>();
}
}} // namespace boost::python

View File

@@ -0,0 +1,30 @@
// Copyright David Abrahams 2004. 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)
#ifndef WRAPPER_DWA2004720_HPP
# define WRAPPER_DWA2004720_HPP
# include <boost/python/detail/wrapper_base.hpp>
# include <boost/python/override.hpp>
# include <boost/python/converter/registered.hpp>
# include <boost/python/detail/sfinae.hpp>
namespace boost { namespace python {
template <class T>
class wrapper : public detail::wrapper_base
{
# if defined(BOOST_PYTHON_NO_SFINAE)
typedef T _wrapper_wrapped_type_;
# endif
protected:
override get_override(char const* name) const
{
return this->wrapper_base::get_override(
name, converter::registered<T>::converters.get_class_object());
}
};
}} // namespace boost::python
#endif // WRAPPER_DWA2004720_HPP

View File

@@ -80,7 +80,7 @@ PyTypeObject life_support_type = {
PyObject* make_nurse_and_patient(PyObject* nurse, PyObject* patient)
{
if (nurse == Py_None)
if (nurse == Py_None || nurse == patient)
return nurse;
if (life_support_type.ob_type == 0)

65
src/wrapper.cpp Executable file
View File

@@ -0,0 +1,65 @@
// Copyright David Abrahams 2004. 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/wrapper.hpp>
namespace boost { namespace python {
namespace detail
{
override wrapper_base::get_override(
char const* name
, PyTypeObject* class_object
) const
{
if (this->m_self)
{
if (handle<> m = handle<>(
python::allow_null(
::PyObject_GetAttrString(
this->m_self, const_cast<char*>(name))))
)
{
PyObject* borrowed_f = 0;
if (
PyMethod_Check(m.get())
&& ((PyMethodObject*)m.get())->im_self == this->m_self
&& class_object->tp_dict != 0
)
{
borrowed_f = ::PyDict_GetItemString(class_object->tp_dict, name);
}
if (borrowed_f != ((PyMethodObject*)m.get())->im_func)
return override(m);
}
}
return override(handle<>(detail::none()));
}
}
#if 0
namespace converter
{
PyObject* BOOST_PYTHON_DECL do_polymorphic_ref_to_python(
python::detail::wrapper_base const volatile* x, type_info src
)
{
if (x == 0)
{
::PyErr_Format(
PyExc_TypeError
, "Attempting to returning pointer or reference to instance of %s\n"
"for which no corresponding Python object exists. Wrap this function"
"with a return return value policy"
)
}
}
}
#endif
}} // namespace boost::python::detail

View File

@@ -99,6 +99,7 @@ bpl-test crossmod_exception
[ bpl-test staticmethod ]
[ bpl-test shared_ptr ]
[ bpl-test polymorphism ]
[ bpl-test polymorphism2 ]
[ bpl-test auto_ptr ]
[ bpl-test minimal ]
[ bpl-test args ]

View File

@@ -74,7 +74,7 @@ void test()
)();
// Retrieve the main module's namespace
python::object main_namespace(main_module.attr("__dict__"));
python::object main_namespace((main_module.attr("__dict__")));
// Define the derived class in Python.
// (You'll normally want to put this in a .py file.)
@@ -115,12 +115,12 @@ test_tutorial()
{
using namespace boost::python;
object main_module(
handle<>(borrowed(PyImport_AddModule("__main__"))));
object main_module((
handle<>(borrowed(PyImport_AddModule("__main__")))));
object main_namespace = main_module.attr("__dict__");
handle<>(PyRun_String(
handle<> ignored((PyRun_String(
"hello = file('hello.txt', 'w')\n"
"hello.write('Hello world!')\n"
@@ -129,7 +129,7 @@ test_tutorial()
, Py_file_input
, main_namespace.ptr()
, main_namespace.ptr())
);
));
}
void
@@ -137,29 +137,29 @@ test_tutorial2()
{
using namespace boost::python;
object main_module(
handle<>(borrowed(PyImport_AddModule("__main__"))));
object main_module((
handle<>(borrowed(PyImport_AddModule("__main__")))));
object main_namespace = main_module.attr("__dict__");
handle<>(PyRun_String(
handle<> ignored((PyRun_String(
"result = 5 ** 2"
, Py_file_input
, main_namespace.ptr()
, main_namespace.ptr())
);
));
int five_squared = extract<int>(main_namespace["result"]);
assert(five_squared == 25);
object result(handle<>(
object result((handle<>(
PyRun_String("5 ** 2"
, Py_eval_input
, main_namespace.ptr()
, main_namespace.ptr()))
);
));
int five_squared2 = extract<int>(result);
assert(five_squared2 == 25);

159
test/polymorphism2.cpp Executable file
View File

@@ -0,0 +1,159 @@
// 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.
#include <boost/python/module.hpp>
#include <boost/python/class.hpp>
#include <boost/python/return_value_policy.hpp>
#include <boost/python/manage_new_object.hpp>
#include <boost/python/reference_existing_object.hpp>
#include <boost/python/pure_virtual.hpp>
#include <boost/python/wrapper.hpp>
#include <boost/python/def.hpp>
#include <boost/python/call.hpp>
#include <boost/utility.hpp>
using namespace boost::python;
struct P
{
virtual ~P(){}
virtual char const* f() = 0;
char const* g() { return "P::g()"; }
};
struct PCallback : P, wrapper<P>
{
char const* f()
{
#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
return call<char const*>(this->get_override("f").ptr());
#else
return this->get_override("f")();
#endif
}
};
struct Q : virtual P
{
char const* f() { return "Q::f()"; }
};
struct A
{
virtual ~A(){}
virtual char const* f() { return "A::f()"; }
};
struct ACallback : A, wrapper<A>
{
char const* f()
{
if (override f = this->get_override("f"))
#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
return call<char const*>(f.ptr());
#else
return f();
#endif
else
return A::f();
}
};
struct B : A
{
virtual char const* f() { return "B::f()"; }
};
struct C : A
{
virtual char const* f() { return "C::f()"; }
};
struct D : A
{
virtual char const* f() { return "D::f()"; }
char const* g() { return "D::g()"; }
};
struct DCallback : D, wrapper<D>
{
char const* f()
{
if (override f = this->get_override("f"))
#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
return call<char const*>(f.ptr());
#else
return f();
#endif
else
return D::f();
}
};
A& getBCppObj ()
{
static B b;
return b;
}
char const* call_f(A& a) { return a.f(); }
A* factory(unsigned choice)
{
switch (choice % 3)
{
case 0: return new A;
break;
case 1: return new B;
break;
default: return new C;
break;
}
}
C& getCCppObj ()
{
static C c;
return c;
}
A* pass_a(A* x) { return x; }
BOOST_PYTHON_MODULE_INIT(polymorphism2_ext)
{
class_<ACallback,boost::noncopyable>("A")
.def("f", &A::f)
;
def("getBCppObj", getBCppObj, return_value_policy<reference_existing_object>());
class_<C,bases<A>,boost::noncopyable>("C")
.def("f", &C::f)
;
class_<DCallback,bases<A>,boost::noncopyable>("D")
.def("f", &D::f)
.def("g", &D::g)
;
def("pass_a", &pass_a, return_internal_reference<>());
def("getCCppObj", getCCppObj, return_value_policy<reference_existing_object>());
def("factory", factory, return_value_policy<manage_new_object>());
def("call_f", call_f);
class_<PCallback,boost::noncopyable>("P")
.def("f", pure_virtual(&P::f))
;
class_<Q, bases<P> >("Q")
.def("g", &P::g) // make sure virtual inheritance doesn't interfere
;
}
//#include "module_tail.cpp"

71
test/polymorphism2.py Normal file
View File

@@ -0,0 +1,71 @@
import unittest
from polymorphism2_ext import *
class PolymorphTest(unittest.TestCase):
def testReturnCpp(self):
# Python Created Object With Same Id As
# Cpp Created B Object
# b = B(872)
# Get Reference To Cpp Created B Object
a = getBCppObj()
# Python Created B Object and Cpp B Object
# Should have same result by calling f()
self.failUnlessEqual ('B::f()', a.f())
self.failUnlessEqual ('B::f()', call_f(a))
self.failUnlessEqual ('A::f()', call_f(A()))
def test_references(self):
# B is not exposed to Python
a = getBCppObj()
self.failUnlessEqual(type(a), A)
# C is exposed to Python
c = getCCppObj()
self.failUnlessEqual(type(c), C)
def test_factory(self):
self.failUnlessEqual(type(factory(0)), A)
self.failUnlessEqual(type(factory(1)), A)
self.failUnlessEqual(type(factory(2)), C)
def test_return_py(self):
class X(A):
def f(self):
return 'X.f'
x = X()
self.failUnlessEqual ('X.f', x.f())
self.failUnlessEqual ('X.f', call_f(x))
def test_wrapper_downcast(self):
a = pass_a(D())
self.failUnlessEqual('D::g()', a.g())
def test_pure_virtual(self):
p = P()
self.assertRaises(RuntimeError, p.f)
q = Q()
self.failUnlessEqual ('Q::f()', q.f())
class R(P):
def f(self):
return 'R.f'
r = R()
self.failUnlessEqual ('R.f', r.f())
if __name__ == "__main__":
# remove the option which upsets unittest
import sys
sys.argv = [ x for x in sys.argv if x != '--broken-auto-ptr' ]
unittest.main()