2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-25 06:22:15 +00:00

Full virtual function and abstract base support; new class interface.

[SVN r13253]
This commit is contained in:
Dave Abrahams
2002-03-24 14:52:30 +00:00
parent d72128107e
commit 0ce8ab7bce
17 changed files with 430 additions and 305 deletions

View File

@@ -7,55 +7,50 @@
# define CLASS_DWA200216_HPP
# include <boost/python/class_fwd.hpp>
# include <boost/python/bases.hpp>
# include <boost/python/args.hpp>
# include <boost/python/reference.hpp>
# include <boost/python/object/class.hpp>
# include <boost/python/object/value_holder_fwd.hpp>
# include <boost/python/converter/type_id.hpp>
# include <boost/python/detail/wrap_function.hpp>
# include <boost/python/detail/member_function_cast.hpp>
# include <boost/mpl/type_list.hpp>
# include <boost/python/object/class_converters.hpp>
# include <boost/type_traits/ice.hpp>
# include <boost/type_traits/same_traits.hpp>
# include <boost/mpl/size.hpp>
# include <boost/mpl/for_each.hpp>
# include <boost/python/detail/type_list.hpp>
namespace // put some convenience classes into the unnamed namespace for the user
{
// A type list for specifying bases
template < BOOST_MPL_LIST_DEFAULT_PARAMETERS(typename B, ::boost::mpl::null_argument) >
struct bases : ::boost::mpl::type_list< BOOST_MPL_LIST_PARAMETERS(B) >::type
{};
// A type list for specifying arguments
template < BOOST_MPL_LIST_DEFAULT_PARAMETERS(typename A, ::boost::mpl::null_argument) >
struct args : ::boost::mpl::type_list< BOOST_MPL_LIST_PARAMETERS(A) >::type
{};
}
# include <boost/mpl/bool_t.hpp>
# include <boost/python/object/select_holder.hpp>
# include <boost/python/object/class_wrapper.hpp>
# include <boost/utility.hpp>
namespace boost { namespace python {
namespace detail
{
// This is an mpl BinaryMetaFunction object with a runtime behavior,
// which is to write the id of the type which is passed as its 2nd
// compile-time argument into the iterator pointed to by its runtime
// argument
struct write_type_id
{
// The first argument is Ignored because mpl::for_each is still
// currently an accumulate (reduce) implementation.
template <class Ignored, class T> struct apply
{
// also an artifact of accumulate-based for_each
typedef void type;
struct write_type_id;
template <class T, class Prev = detail::not_specified>
struct select_held_type;
template <class T1, class T2, class T3>
struct has_noncopyable;
// Here's the runtime behavior
static void execute(converter::undecorated_type_id_t** p)
{
*(*p)++ = converter::undecorated_type_id<T>();
}
};
};
// Register a to_python converter for a class T, depending on the
// type of the first (tag) argument. The 2nd argument is a pointer
// to the type of holder that must be created. The 3rd argument is a
// reference to the Python type object to be created.
template <class T, class Holder>
static inline void register_copy_constructor(mpl::bool_t<true> const&, Holder*, ref const& obj, T* = 0)
{
objects::class_wrapper<T,Holder> x(obj);
}
// Tag dispatched to have no effect.
template <class T, class Holder>
static inline void register_copy_constructor(mpl::bool_t<false> const&, Holder*, ref const&, T* = 0)
{
}
}
//
@@ -64,27 +59,24 @@ namespace detail
// This is the primary mechanism through which users will expose
// C++ classes to Python. The three template arguments are:
//
// T - The class being exposed to Python
//
// Bases - An MPL sequence of base classes
//
// HolderGenerator -
// An optional type generator for the "holder" which
// maintains the C++ object inside the Python instance. The
// default just holds the object "by-value", but other
// holders can be substituted which will hold the C++ object
// by smart pointer, for example.
//
template <
class T // class being wrapped
, class Bases
, class HolderGenerator
, class X1 // = detail::not_specified
, class X2 // = detail::not_specified
, class X3 // = detail::not_specified
>
class class_ : private objects::class_base
{
typedef class_<T,Bases,HolderGenerator> self;
typedef class_<T,X1,X2,X3> self;
BOOST_STATIC_CONSTANT(bool, is_copyable = (!detail::has_noncopyable<X1,X2,X3>::value));
typedef typename detail::select_held_type<
X1, typename detail::select_held_type<
X2, typename detail::select_held_type<
X3
>::type>::type>::type held_type;
public:
// Automatically derive the class name - only works on some
// compilers because type_info::name is sometimes mangled (gcc)
class_();
@@ -130,7 +122,12 @@ class class_ : private objects::class_base
template <class Args>
self& def_init(Args const&)
{
def("__init__", make_constructor<T,Args,HolderGenerator>());
def("__init__",
make_constructor<Args>(
// Using runtime type selection works around a CWPro7 bug.
objects::select_holder<T,held_type>((held_type*)0).get()
)
);
return *this;
}
@@ -147,6 +144,12 @@ class class_ : private objects::class_base
private: // types
typedef objects::class_id class_id;
typedef typename detail::select_bases<X1
, typename detail::select_bases<X2
, typename boost::python::detail::select_bases<X3>::type
>::type
>::type bases;
// A helper class which will contain an array of id objects to be
// passed to the base class constructor
struct id_vector
@@ -159,50 +162,97 @@ class class_ : private objects::class_base
// Write the rest of the elements into succeeding positions.
class_id* p = ids + 1;
mpl::for_each<Bases, void, detail::write_type_id>::execute(&p);
mpl::for_each<bases, void, detail::write_type_id>::execute(&p);
}
BOOST_STATIC_CONSTANT(
std::size_t, size = mpl::size<Bases>::value + 1);
std::size_t, size = mpl::size<bases>::value + 1);
class_id ids[size];
};
private: // helper functions
void initialize_converters();
};
//
// implementations
//
template <class T, class Bases, class HolderGenerator>
inline class_<T, Bases, HolderGenerator>::class_()
template <class T, class X1, class X2, class X3>
inline class_<T,X1,X2,X3>::class_()
: class_base(typeid(T).name(), id_vector::size, id_vector().ids)
{
// Bring the class converters into existence. This static object
// will survive until the shared library this module lives in is
// unloaded (that doesn't happen until Python terminates).
static objects::class_converters<T,Bases> converters(object());
// register converters
objects::register_class_from_python<T,bases>();
detail::register_copy_constructor<T>(
mpl::bool_t<is_copyable>()
, objects::select_holder<T,held_type>((held_type*)0).get()
, this->object());
}
template <class T, class Bases, class HolderGenerator>
inline class_<T, Bases, HolderGenerator>::class_(char const* name)
template <class T, class X1, class X2, class X3>
inline class_<T,X1,X2,X3>::class_(char const* name)
: class_base(name, id_vector::size, id_vector().ids)
{
// Bring the class converters into existence. This static object
// will survive until the shared library this module lives in is
// unloaded (that doesn't happen until Python terminates).
static objects::class_converters<T,Bases> converters(object());
// register converters
objects::register_class_from_python<T,bases>();
detail::register_copy_constructor<T>(
mpl::bool_t<is_copyable>()
, objects::select_holder<T,held_type>((held_type*)0).get()
, this->object());
}
template <class T, class Bases, class HolderGenerator>
inline ref class_<T, Bases, HolderGenerator>::object() const
template <class T, class X1, class X2, class X3>
inline ref class_<T,X1,X2,X3>::object() const
{
typedef objects::class_base base;
return this->base::object();
}
namespace detail
{
// This is an mpl BinaryMetaFunction object with a runtime behavior,
// which is to write the id of the type which is passed as its 2nd
// compile-time argument into the iterator pointed to by its runtime
// argument
struct write_type_id
{
// The first argument is Ignored because mpl::for_each is still
// currently an accumulate (reduce) implementation.
template <class Ignored, class T> struct apply
{
// also an artifact of accumulate-based for_each
typedef void type;
// Here's the runtime behavior
static void execute(converter::undecorated_type_id_t** p)
{
*(*p)++ = converter::undecorated_type_id<T>();
}
};
};
template <class T1, class T2, class T3>
struct has_noncopyable
: type_traits::ice_or<
is_same<T1,noncopyable>::value
, is_same<T2,noncopyable>::value
, is_same<T3,noncopyable>::value>
{};
template <class T, class Prev>
struct select_held_type
: mpl::select_type<
!(specifies_bases<T>::value | is_same<T,noncopyable>::value)
, T
, Prev
>
{
};
}
}} // namespace boost::python
#endif // CLASS_DWA200216_HPP

View File

@@ -5,7 +5,7 @@
// to its suitability for any purpose.
#ifndef CLASS_FWD_DWA200222_HPP
# define CLASS_FWD_DWA200222_HPP
# include <boost/python/object/value_holder_fwd.hpp>
# include <boost/python/detail/not_specified.hpp>
namespace boost { namespace python {
@@ -16,8 +16,9 @@ namespace detail
template <
class T // class being wrapped
, class Bases = detail::empty_list
, class HolderGenerator = objects::value_holder_generator<>
, class X1 = detail::not_specified
, class X2 = detail::not_specified
, class X3 = detail::not_specified
>
class class_;

View File

@@ -103,7 +103,7 @@ struct arg_tuple_size<R (A0::*)(A1, A2, A3, A4, A5)>
// Metrowerks thinks this creates ambiguities
# if !defined(__MWERKS__) || __MWERKS__ > 0x2406
# if !defined(__MWERKS__) || __MWERKS__ > 0x2407
template <class R, class A0>
struct arg_tuple_size<R (A0::*)() const>

View File

@@ -8,7 +8,8 @@
#include <boost/type.hpp>
#include <typeinfo>
#include <boost/type_traits/array_traits.hpp>
#include <boost/type_traits/reference_traits.hpp>
//
// Fix for MSVC's broken typeid() implementation which doesn't strip
// decoration. This fix doesn't handle cv-qualified array types. It
@@ -62,35 +63,35 @@ inline typeinfo typeid_nonref(boost::type<T>* = 0)
}
template <class T>
inline typeinfo typeid_ref(boost::type<T>*, ...)
{
return typeid_nonref<T>();
}
template <class U, class T>
inline typeinfo typeid_ref(boost::type<U>*, T& (*)())
inline typeinfo typeid_ref(T&(*)())
{
return typeid_nonref<T>();
}
template <class T>
inline typeinfo typeid_array(bool_t<false>, boost::type<T>* = 0)
inline typeinfo array_ref_typeid(bool_t<true>, bool_t<false>, boost::type<T>* = 0)
{
typedef T (*x)();
return typeid_ref((boost::type<T>*)0, x(0));
return typeid_ref((T&(*)())0);
}
template <class T>
inline typeinfo typeid_array(bool_t<true>, boost::type<T>* = 0)
inline typeinfo array_ref_typeid(bool_t<false>, bool_t<true>, boost::type<T>* = 0)
{
return typeid_nonref<T>();
return typeid_ref((T(*)())0);
}
template <class T>
inline typeinfo array_ref_typeid(bool_t<false>, bool_t<false>, boost::type<T>* = 0)
{
return typeid_ref((T&(*)())0);
}
template <class T>
inline typeinfo msvc_typeid(boost::type<T>* = 0)
{
typedef bool_t<is_array<T>::value> tag;
return typeid_array(tag(), (boost::type<T>*)0);
typedef bool_t<is_array<T>::value> array_tag;
typedef bool_t<is_reference<T>::value> ref_tag;
return array_ref_typeid(array_tag(), ref_tag(), (boost::type<T>*)0);
}
}}} // namespace boost::python::detail

View File

@@ -35,8 +35,8 @@ objects::function* make_function(F f, Policies const& policies)
, detail::arg_tuple_size<F>::value);
}
template <class T, class ArgList, class Generator>
objects::function* make_constructor(T* = 0, ArgList* = 0, Generator* = 0)
template <class ArgList, class Holder>
objects::function* make_constructor(Holder* = 0, ArgList* = 0)
{
enum { nargs = mpl::size<ArgList>::value };
@@ -44,7 +44,7 @@ objects::function* make_constructor(T* = 0, ArgList* = 0, Generator* = 0)
objects::py_function(
::boost::bind<PyObject*>(detail::caller(),
objects::make_holder<nargs>
::template apply<T,Generator,ArgList>::execute
::template apply<Holder,ArgList>::execute
, _1, _2, default_call_policies()))
, nargs + 1);
}

View File

@@ -11,27 +11,10 @@
# include <boost/python/reference.hpp>
# include <boost/python/converter/registry.hpp>
# include <boost/python/object/find_instance.hpp>
# include <boost/python/object/inheritance.hpp>
namespace boost { namespace python { namespace objects {
// Instantiating this class brings into existence all converters
// associated with a class Bases is expected to be an mpl sequence of
// base types.
template <class Derived, class Bases>
struct class_converters
{
public: // member functions
// Constructor takes the python class object associated with T
class_converters(ref const& python_class);
private: // data members
class_wrapper<Derived> m_wrapper;
};
//
// Implementation details
//
//////////////////////////////////////////////////////////////////////
//
// register_base_of<T> -
@@ -86,9 +69,11 @@ struct register_base_of
};
};
// Brings into existence all converters associated with a class Bases
// is expected to be an mpl sequence of base types.
template <class Derived, class Bases>
class_converters<Derived,Bases>::class_converters(ref const& type_object)
: m_wrapper(type_object)
inline void register_class_from_python(Derived* = 0, Bases* = 0)
{
(void)instance_finder<Derived>::registration;

View File

@@ -6,15 +6,14 @@
#ifndef CLASS_WRAPPER_DWA20011221_HPP
# define CLASS_WRAPPER_DWA20011221_HPP
# include <boost/python/object/value_holder.hpp>
# include <boost/python/reference.hpp>
# include <boost/python/to_python_converter.hpp>
namespace boost { namespace python { namespace objects {
template <class T>
template <class T, class Holder>
struct class_wrapper
: to_python_converter<T, class_wrapper<T> >
: to_python_converter<T,class_wrapper<T,Holder> >
{
class_wrapper(ref const& type_)
: m_class_object_keeper(type_)
@@ -39,7 +38,7 @@ struct class_wrapper
// Build a value_holder to contain the object using the copy
// constructor
value_holder<T>* p = new value_holder<T>(raw_result, cref(x));
Holder* p = new Holder(raw_result, cref(x));
// Install it in the instance
p->install(raw_result);
@@ -53,8 +52,8 @@ struct class_wrapper
static PyTypeObject* m_class_object;
};
template <class T>
PyTypeObject* class_wrapper<T>::m_class_object;
template <class T, class Holder>
PyTypeObject* class_wrapper<T,Holder>::m_class_object;
}}} // namespace boost::python::objects

View File

@@ -6,6 +6,9 @@
#ifndef FIND_INSTANCE_DWA2002312_HPP
# define FIND_INSTANCE_DWA2002312_HPP
# include <boost/python/converter/type_id.hpp>
# include <boost/python/converter/registry.hpp>
namespace boost { namespace python { namespace objects {
// Given an undecorated type_id, find the instance data which

View File

@@ -10,7 +10,6 @@
# include <boost/python/object/forward.hpp>
# include <boost/python/object/class.hpp>
# include <boost/python/detail/wrap_python.hpp>
# include <boost/mpl/apply.hpp>
namespace boost { namespace python { namespace objects {
@@ -19,14 +18,13 @@ template <int nargs> struct make_holder;
template <>
struct make_holder<0>
{
template <class T, class Generator, class ArgList>
template <class Holder, class ArgList>
struct apply
{
typedef typename mpl::apply1<Generator,T>::type holder;
static void execute(
PyObject* p)
{
(new holder(p))->install(p);
(new Holder(p))->install(p);
}
};
};
@@ -35,10 +33,9 @@ struct make_holder<0>
template <>
struct make_holder<1>
{
template <class T, class Generator, class ArgList>
template <class Holder, class ArgList>
struct apply
{
typedef typename mpl::apply1<Generator,T>::type holder;
typedef typename mpl::at<0,ArgList>::type t0;
typedef typename forward<t0>::type f0;
@@ -46,7 +43,7 @@ struct make_holder<1>
PyObject* p
, t0 a0)
{
(new holder(p, f0(a0)))->install(p);
(new Holder(p, f0(a0)))->install(p);
}
};
};
@@ -54,10 +51,9 @@ struct make_holder<1>
template <>
struct make_holder<2>
{
template <class T, class Generator, class ArgList>
template <class Holder, class ArgList>
struct apply
{
typedef typename mpl::apply1<Generator,T>::type holder;
typedef typename mpl::at<0,ArgList>::type t0;
typedef typename forward<t0>::type f0;
typedef typename mpl::at<1,ArgList>::type t1;
@@ -66,7 +62,7 @@ struct make_holder<2>
static void execute(
PyObject* p, t0 a0, t1 a1)
{
(new holder(p, f0(a0), f1(a1)))->install(p);
(new Holder(p, f0(a0), f1(a1)))->install(p);
}
};
};
@@ -74,10 +70,9 @@ struct make_holder<2>
template <>
struct make_holder<3>
{
template <class T, class Generator, class ArgList>
template <class Holder, class ArgList>
struct apply
{
typedef typename mpl::apply1<Generator,T>::type holder;
typedef typename mpl::at<0,ArgList>::type t0;
typedef typename forward<t0>::type f0;
typedef typename mpl::at<1,ArgList>::type t1;
@@ -88,7 +83,7 @@ struct make_holder<3>
static void execute(
PyObject* p, t0 a0, t1 a1, t2 a2)
{
(new holder(p, f0(a0), f1(a1), f2(a2)))->install(p);
(new Holder(p, f0(a0), f1(a1), f2(a2)))->install(p);
}
};
};
@@ -96,10 +91,9 @@ struct make_holder<3>
template <>
struct make_holder<4>
{
template <class T, class Generator, class ArgList>
template <class Holder, class ArgList>
struct apply
{
typedef typename mpl::apply1<Generator,T>::type holder;
typedef typename mpl::at<0,ArgList>::type t0;
typedef typename forward<t0>::type f0;
typedef typename mpl::at<1,ArgList>::type t1;
@@ -112,7 +106,7 @@ struct make_holder<4>
static void execute(
PyObject* p, t0 a0, t1 a1, t2 a2, t3 a3)
{
(new holder(p, f0(a0), f1(a1), f2(a2), f3(a3)))->install(p);
(new Holder(p, f0(a0), f1(a1), f2(a2), f3(a3)))->install(p);
}
};
};
@@ -120,10 +114,9 @@ struct make_holder<4>
template <>
struct make_holder<5>
{
template <class T, class Generator, class ArgList>
template <class Holder, class ArgList>
struct apply
{
typedef typename mpl::apply1<Generator,T>::type holder;
typedef typename mpl::at<0,ArgList>::type t0;
typedef typename forward<t0>::type f0;
typedef typename mpl::at<1,ArgList>::type t1;
@@ -138,7 +131,7 @@ struct make_holder<5>
static void execute(
PyObject* p, t0 a0, t1 a1, t2 a2, t3 a3, t4 a4)
{
(new holder(p, f0(a0), f1(a1), f2(a2), f3(a3), f4(a4)))->install(p);
(new Holder(p, f0(a0), f1(a1), f2(a2), f3(a3), f4(a4)))->install(p);
}
};
};
@@ -146,10 +139,9 @@ struct make_holder<5>
template <>
struct make_holder<6>
{
template <class T, class Generator, class ArgList>
template <class Holder, class ArgList>
struct apply
{
typedef typename mpl::apply1<Generator,T>::type holder;
typedef typename mpl::at<0,ArgList>::type t0;
typedef typename forward<t0>::type f0;
typedef typename mpl::at<1,ArgList>::type t1;
@@ -166,7 +158,7 @@ struct make_holder<6>
static void execute(
PyObject* p, t0 a0, t1 a1, t2 a2, t3 a3, t4 a4, t5 a5)
{
(new holder(p, f0(a0), f1(a1), f2(a2), f3(a3), f4(a4), f5(a5)))->install(p);
(new Holder(p, f0(a0), f1(a1), f2(a2), f3(a3), f4(a4), f5(a5)))->install(p);
}
};
};

View File

@@ -14,6 +14,7 @@
# include <boost/type.hpp>
# include <boost/mpl/select_type.hpp>
# include <boost/mpl/apply.hpp>
# include <boost/python/detail/pointee.hpp>
namespace boost { namespace python { namespace objects {
@@ -147,81 +148,83 @@ struct pointer_holder : instance_holder
Pointer m_p;
};
template <class Pointer, class Value, class BackReferenceType>
template <class Pointer, class Value>
struct pointer_holder_back_reference : instance_holder
{
private:
typedef typename python::detail::pointee<Pointer>::type held_type;
public:
pointer_holder_back_reference(Pointer);
// Forward construction to the held object
pointer_holder_back_reference(PyObject* p)
: m_p(new BackReferenceType(p)) {
(void)instance_finder<BackReferenceType>::registration;
: m_p(new held_type(p)) {
(void)instance_finder<held_type>::registration;
}
template <class A1>
pointer_holder_back_reference(PyObject* p, A1 a1)
: m_p(new BackReferenceType(p
: m_p(new held_type(p
, (typename unwrap_reference<A1>::type&)(a1)
))
{
(void)instance_finder<BackReferenceType>::registration;
(void)instance_finder<held_type>::registration;
}
template <class A1, class A2>
pointer_holder_back_reference(PyObject* p, A1 a1, A2 a2)
: m_p(new BackReferenceType(p
: m_p(new held_type(p
, (typename unwrap_reference<A1>::type&)(a1)
, (typename unwrap_reference<A2>::type&)(a2)
))
{
(void)instance_finder<BackReferenceType>::registration;
(void)instance_finder<held_type>::registration;
}
template <class A1, class A2, class A3>
pointer_holder_back_reference(PyObject* p, A1 a1, A2 a2, A3 a3)
: m_p(new BackReferenceType(p
: m_p(new held_type(p
, (typename unwrap_reference<A1>::type&)(a1)
, (typename unwrap_reference<A2>::type&)(a2)
, (typename unwrap_reference<A3>::type&)(a3)
))
{
(void)instance_finder<BackReferenceType>::registration;
(void)instance_finder<held_type>::registration;
}
template <class A1, class A2, class A3, class A4>
pointer_holder_back_reference(PyObject* p, A1 a1, A2 a2, A3 a3, A4 a4)
: m_p(new BackReferenceType(p
: m_p(new held_type(p
, (typename unwrap_reference<A1>::type&)(a1)
, (typename unwrap_reference<A2>::type&)(a2)
, (typename unwrap_reference<A3>::type&)(a3)
, (typename unwrap_reference<A4>::type&)(a4)
))
{
(void)instance_finder<BackReferenceType>::registration;
(void)instance_finder<held_type>::registration;
}
template <class A1, class A2, class A3, class A4, class A5>
pointer_holder_back_reference(PyObject* p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5)
: m_p(new BackReferenceType(p
: m_p(new held_type(p
, (typename unwrap_reference<A1>::type&)(a1)
, (typename unwrap_reference<A2>::type&)(a2)
, (typename unwrap_reference<A3>::type&)(a3)
, (typename unwrap_reference<A4>::type&)(a4)
, (typename unwrap_reference<A5>::type&)(a5)
)) {
(void)instance_finder<BackReferenceType>::registration;
(void)instance_finder<held_type>::registration;
}
template <class A1, class A2, class A3, class A4, class A5, class A6>
pointer_holder_back_reference(PyObject* p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6)
: m_p(new BackReferenceType(p
: m_p(new held_type(p
, (typename unwrap_reference<A1>::type&)(a1)
, (typename unwrap_reference<A2>::type&)(a2)
, (typename unwrap_reference<A3>::type&)(a3)
@@ -229,13 +232,13 @@ struct pointer_holder_back_reference : instance_holder
, (typename unwrap_reference<A5>::type&)(a5)
, (typename unwrap_reference<A6>::type&)(a6)
)) {
(void)instance_finder<BackReferenceType>::registration;
(void)instance_finder<held_type>::registration;
}
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7>
pointer_holder_back_reference(PyObject* p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7)
: m_p(new BackReferenceType(p
: m_p(new held_type(p
, (typename unwrap_reference<A1>::type&)(a1)
, (typename unwrap_reference<A2>::type&)(a2)
, (typename unwrap_reference<A3>::type&)(a3)
@@ -245,13 +248,13 @@ struct pointer_holder_back_reference : instance_holder
, (typename unwrap_reference<A7>::type&)(a7)
))
{
(void)instance_finder<BackReferenceType>::registration;
(void)instance_finder<held_type>::registration;
}
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8>
pointer_holder_back_reference(PyObject* p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8)
: m_p(new BackReferenceType(p
: m_p(new held_type(p
, (typename unwrap_reference<A1>::type&)(a1)
, (typename unwrap_reference<A2>::type&)(a2)
, (typename unwrap_reference<A3>::type&)(a3)
@@ -262,13 +265,13 @@ struct pointer_holder_back_reference : instance_holder
, (typename unwrap_reference<A8>::type&)(a8)
))
{
(void)instance_finder<BackReferenceType>::registration;
(void)instance_finder<held_type>::registration;
}
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9>
pointer_holder_back_reference(PyObject* p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9)
: m_p(new BackReferenceType(p
: m_p(new held_type(p
, (typename unwrap_reference<A1>::type&)(a1)
, (typename unwrap_reference<A2>::type&)(a2)
, (typename unwrap_reference<A3>::type&)(a3)
@@ -280,13 +283,13 @@ struct pointer_holder_back_reference : instance_holder
, (typename unwrap_reference<A9>::type&)(a9)
))
{
(void)instance_finder<BackReferenceType>::registration;
(void)instance_finder<held_type>::registration;
}
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9, class A10>
pointer_holder_back_reference(PyObject* p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10)
: m_p(new BackReferenceType(p
: m_p(new held_type(p
, (typename unwrap_reference<A1>::type&)(a1)
, (typename unwrap_reference<A2>::type&)(a2)
, (typename unwrap_reference<A3>::type&)(a3)
@@ -299,7 +302,7 @@ struct pointer_holder_back_reference : instance_holder
, (typename unwrap_reference<A10>::type&)(a10)
))
{
(void)instance_finder<BackReferenceType>::registration;
(void)instance_finder<held_type>::registration;
}
@@ -310,81 +313,18 @@ struct pointer_holder_back_reference : instance_holder
Pointer m_p;
};
}}} // namespace boost::python::objects
// back to namespace boost for this forward declaration
namespace boost
{
template <class T> class shared_ptr;
}
namespace boost { namespace python { namespace objects {
struct shared_ptr_generator
{
template <class T>
struct apply
{
typedef boost::shared_ptr<T> type;
};
};
struct no_back_reference;
// Workaround lack of partial specialization
namespace detail
{
template <class BackReferenceType, class PointerGenerator>
struct pointer_holder_back_reference_generator
{
template <class Held>
struct apply
{
typedef typename mpl::apply1<
PointerGenerator,BackReferenceType
>::type pointer;
typedef pointer_holder_back_reference<pointer,Held,BackReferenceType> type;
};
};
template <class PointerGenerator>
struct plain_pointer_holder_generator
{
template <class Held>
struct apply
{
typedef typename mpl::apply1<
PointerGenerator,Held
>::type pointer;
typedef pointer_holder<pointer, Held> type;
};
};
}
// A generator metafunction which can be passed to make_holder
// PointerGenerator should be another generator metafunction which
// makes the appropriate (smart) pointer type to hold the argument to
// pointer_holder_generator.
template <class PointerGenerator, class BackReferenceType = no_back_reference>
struct pointer_holder_generator
: mpl::select_type<
is_same<BackReferenceType,no_back_reference>::value
, detail::plain_pointer_holder_generator<
PointerGenerator>
, detail::pointer_holder_back_reference_generator<
BackReferenceType,PointerGenerator>
>::type
{
};
template <class Pointer, class Value>
pointer_holder<Pointer,Value>::pointer_holder(Pointer p)
: m_p(p)
{
}
template <class Pointer, class Value>
pointer_holder_back_reference<Pointer,Value>::pointer_holder_back_reference(Pointer p)
: m_p(p)
{
}
template <class Pointer, class Value>
void* pointer_holder<Pointer, Value>::holds(converter::undecorated_type_id_t dst_t)
{
@@ -396,6 +336,20 @@ void* pointer_holder<Pointer, Value>::holds(converter::undecorated_type_id_t dst
: find_dynamic_type(&*this->m_p, src_t, dst_t);
}
template <class Pointer, class Value>
void* pointer_holder_back_reference<Pointer, Value>::holds(converter::undecorated_type_id_t dst_t)
{
if (dst_t == converter::undecorated_type_id<Pointer>())
return &this->m_p;
if (dst_t == converter::undecorated_type_id<held_type>())
return &*this->m_p;
converter::type_id_t src_t = converter::undecorated_type_id<Value>();
Value* p = &*this->m_p;
return src_t == dst_t ? p : find_dynamic_type(p, src_t, dst_t);
}
}}} // namespace boost::python::objects
#endif // POINTER_HOLDER_DWA20011215_HPP

View File

@@ -0,0 +1,70 @@
// 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 SELECT_HOLDER_DWA2002322_HPP
# define SELECT_HOLDER_DWA2002322_HPP
# include <boost/python/has_back_reference.hpp>
# include <boost/python/detail/not_specified.hpp>
# include <boost/python/detail/pointee.hpp>
# include <boost/python/detail/if_else.hpp>
# include <boost/python/object/value_holder.hpp>
# include <boost/python/object/pointer_holder.hpp>
# include <boost/type.hpp>
# include <boost/mpl/select_type.hpp>
namespace boost { namespace python { namespace objects {
namespace detail
{
template <class T, class Held>
struct select_value_holder
{
typedef typename mpl::select_type<
(!is_same<T,Held>::value) | has_back_reference<T>::value
, value_holder_back_reference<T,Held>
, value_holder<T>
>::type holder;
static holder* get() { return 0; }
};
template <class T,class Ptr>
struct select_pointer_holder
{
typedef typename python::detail::pointee<Ptr>::type pointee;
typedef typename mpl::select_type<
(!is_same<pointee,T>::value) | has_back_reference<T>::value
, pointer_holder_back_reference<Ptr,T>
, pointer_holder<Ptr,T>
>::type holder;
static holder* get() { return 0; }
};
}
template <class T, class NotSpecified>
inline detail::select_value_holder<T,T> select_holder(python::detail::not_specified*, T* = 0, NotSpecified* = 0)
{
return detail::select_value_holder<T,T>();
}
template <class T, class Held>
inline detail::select_value_holder<T, Held> select_holder(T*, Held* = 0)
{
return detail::select_value_holder<T, Held>();
}
template <class T, class Ptr>
detail::select_pointer_holder<T,Ptr> select_holder(void*, Ptr* = 0, T* = 0)
{
return detail::select_pointer_holder<T,Ptr>();
}
}}} // namespace boost::python::objects
#endif // SELECT_HOLDER_DWA2002322_HPP

View File

@@ -142,7 +142,7 @@ struct value_holder : instance_holder
Held m_held;
};
template <class Held,class BackReferenceType>
template <class Held, class BackReferenceType>
struct value_holder_back_reference : instance_holder
{
// Forward construction to the held object
@@ -301,27 +301,6 @@ struct value_holder_back_reference : instance_holder
BackReferenceType m_held;
};
// A generator metafunction which can be passed to make_holder
template <>
struct value_holder_generator<no_back_reference>
{
template <class Held>
struct apply
{
typedef value_holder<Held> type;
};
};
template <class BackReferenceType>
struct value_holder_generator
{
template <class Held>
struct apply
{
typedef value_holder_back_reference<Held,BackReferenceType> type;
};
};
template <class Held>
void* value_holder<Held>::holds(converter::undecorated_type_id_t dst_t)
{

View File

@@ -68,6 +68,20 @@ unit-test pointer_type_id_test
unit-test member_function_cast
: member_function_cast.cpp : <include>$(BOOST_ROOT) ;
unit-test bases
: bases.cpp : <include>$(BOOST_ROOT) ;
unit-test if_else
: if_else.cpp : <include>$(BOOST_ROOT) ;
unit-test pointee
: pointee.cpp : <include>$(BOOST_ROOT) ;
unit-test select_holder
: select_holder.cpp
: <include>$(BOOST_ROOT) <define>BOOST_PYTHON_STATIC_LIB $(PYTHON_PROPERTIES)
;
unit-test select_from_python_test
: select_from_python_test.cpp
../src/converter/type_id.cpp
@@ -77,3 +91,4 @@ unit-test select_from_python_test
$(PYTHON_V1_PROPERTIES)
;

View File

@@ -201,6 +201,7 @@ BOOST_PYTHON_MODULE_INIT(m1)
{
using namespace boost::python;
using boost::mpl::type_list;
using boost::shared_ptr;
simple_to_python();
@@ -219,10 +220,6 @@ BOOST_PYTHON_MODULE_INIT(m1)
module m1("m1");
typedef boost::python::objects::pointer_holder_generator<
boost::python::objects::shared_ptr_generator
> use_shared_ptr;
m1
// Insert the metaclass for all extension classes
.setattr("xclass", boost::python::objects::class_metatype())
@@ -251,7 +248,7 @@ BOOST_PYTHON_MODULE_INIT(m1)
.def("take_d", take_d)
.add(
class_<A, bases<>, use_shared_ptr>("A")
class_<A, shared_ptr<A> >("A")
.def_init()
.def("name", &A::name)
)
@@ -262,13 +259,13 @@ BOOST_PYTHON_MODULE_INIT(m1)
// or "C" below if we make them part of the same chain
m1
.add(
class_<B,bases<A>, use_shared_ptr>("B")
class_<B,bases<A>, shared_ptr<B> >("B")
.def_init()
.def("name", &B::name)
)
.add(
class_<C,bases<A>, use_shared_ptr>("C")
class_<C,bases<A>, shared_ptr<C> >("C")
.def_init()
.def("name", &C::name)
)
@@ -276,7 +273,7 @@ BOOST_PYTHON_MODULE_INIT(m1)
m1
.add(
class_<D,bases<B,C>, use_shared_ptr>("D")
class_<D,shared_ptr<D>, bases<B,C> >("D")
.def_init()
.def("name", &D::name)
)

77
test/select_holder.cpp Normal file
View File

@@ -0,0 +1,77 @@
// 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/static_assert.hpp>
#include <boost/type_traits/same_traits.hpp>
#include <boost/python/object/select_holder.hpp>
#include <boost/python/has_back_reference.hpp>
#include <boost/python/detail/not_specified.hpp>
#include <memory>
#define BOOST_INCLUDE_MAIN
#include <boost/test/test_tools.hpp>
struct BR {};
struct Base {};
struct Derived : Base {};
namespace boost { namespace python
{
// specialization
template <>
struct has_back_reference<BR>
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
}} // namespace boost::python
template <class T, class U>
void assert_same(U* = 0, T* = 0)
{
BOOST_TEST((boost::is_same<T,U>::value));
BOOST_STATIC_ASSERT((boost::is_same<T,U>::value));
}
template <class T, class Held, class Holder>
void assert_holder(T* = 0, Held* = 0, Holder* = 0)
{
assert_same<Holder>(boost::python::objects::select_holder<T,Held>((Held*)0).get());
}
int test_main(int, char * [])
{
using namespace boost::python::detail;
using namespace boost::python::objects;
assert_holder<Base,not_specified,value_holder<Base> >();
assert_holder<BR,not_specified,value_holder_back_reference<BR,BR> >();
assert_holder<Base,Base,value_holder<Base> >();
assert_holder<BR,BR,value_holder_back_reference<BR,BR> >();
assert_holder<Base,Derived
,value_holder_back_reference<Base,Derived> >();
assert_holder<Base,std::auto_ptr<Base>
,pointer_holder<std::auto_ptr<Base>,Base> >();
assert_holder<Base,std::auto_ptr<Derived>
,pointer_holder_back_reference<std::auto_ptr<Derived>,Base> >();
assert_holder<BR,std::auto_ptr<BR>
,pointer_holder_back_reference<std::auto_ptr<BR>,BR> > ();
return 0;
}
#if defined(__GNUC__) && __GNUC__ <= 3
// This definition is needed for MinGW 2.95.2 for some reason
namespace boost { namespace python
{
bool handle_exception_impl(boost::function0<void>) { return false; }
}}
#endif

View File

@@ -7,6 +7,7 @@
#include <boost/python/module.hpp>
#include <boost/python/returning.hpp>
#include <boost/ref.hpp>
#include <boost/utility.hpp>
using namespace boost::python;
@@ -66,6 +67,10 @@ struct concrete_callback : concrete
: concrete(x), self(p)
{}
concrete_callback(PyObject* p, concrete const& x)
: concrete(x), self(p)
{}
int f(Y const& y)
{
return returning<int>::call_method(self, "f", boost::ref(y));
@@ -85,26 +90,21 @@ BOOST_PYTHON_MODULE_INIT(virtual_functions_ext)
{
module("virtual_functions_ext")
.add(
class_<concrete, bases<>, objects::value_holder_generator<concrete_callback> >("concrete")
class_<concrete, concrete_callback>("concrete")
.def_init(args<int>())
.def("value", &concrete::value)
.def("set", &concrete::set)
.def("call_f", &concrete::call_f)
.def("f", &concrete_callback::f_impl))
#if 0
.add(
class_<abstract, bases<>
, objects::pointer_holder_generator<
boost::python::objects::shared_ptr_generator
, abstract_callback>
class_<abstract, boost::noncopyable, boost::shared_ptr<abstract_callback>
>("abstract")
.def_init(args<int>())
.def("value", &abstract::value)
.def("call_f", &abstract::call_f)
.def("set", &abstract::set))
#endif
.add(
class_<Y>("Y")

View File

@@ -8,13 +8,13 @@
>>> class C2(concrete):
... pass
<<<>>> class A1(abstract):
<<<... def f(self, y):
<<<... return abstract.f(self, Y(-y.value()))
<<<
<<<>>> class A2(abstract):
<<<... pass
<<<
>>> class A1(abstract):
... def f(self, y):
... return y.value() * 2
>>> class A2(abstract):
... pass
>>> y1 = Y(16)
>>> y2 = Y(17)
@@ -24,33 +24,35 @@
#
# Test abstract with f overridden
#
<<<>>> a1 = A1(42)
<<<>>> a1.value()
<<<42
<<<
<<<# Call f indirectly from C++
<<<>>> a1.call_f(y1)
<<<-16
<<<
<<<# Call f directly from Python
<<<>>> a1.f(y2)
<<<-17
<<<
<<<#
<<<# Test abstract with f not overridden
<<<#
<<<>>> a2 = A2(42)
<<<>>> A2.value()
<<<42
<<<
<<<# Call f indirectly from C++
<<<>>> c1.call_f(y1)
<<<16
<<<
<<<# Call f directly from Python
<<<>>> c1.f(y2)
<<<17
<<<
>>> a1 = A1(42)
>>> a1.value()
42
# Call f indirectly from C++
>>> a1.call_f(y1)
32
# Call f directly from Python
>>> a1.f(y2)
34
#
# Test abstract with f not overridden
#
>>> a2 = A2(42)
>>> a2.value()
42
# Call f indirectly from C++
>>> try: a2.call_f(y1)
... except AttributeError: pass
... else: print 'no exception'
# Call f directly from Python
>>> try: a2.call_f(y2)
... except AttributeError: pass
... else: print 'no exception'
############# Concrete Tests ############
#