Skip to content

Commit 5008dcb

Browse files
committed
Make sure the class object and cast relationships are registered for
virtual function dispatch classes. [SVN r19543]
1 parent 9c66509 commit 5008dcb

File tree

7 files changed

+109
-33
lines changed

7 files changed

+109
-33
lines changed

include/boost/python/class.hpp

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,6 @@
2020
# include <boost/python/init.hpp>
2121
# include <boost/python/args_fwd.hpp>
2222

23-
# include <boost/type_traits/is_same.hpp>
24-
# include <boost/type_traits/is_convertible.hpp>
25-
# include <boost/type_traits/is_member_function_pointer.hpp>
26-
# include <boost/type_traits/is_polymorphic.hpp>
27-
28-
# include <boost/mpl/size.hpp>
29-
# include <boost/mpl/for_each.hpp>
30-
# include <boost/mpl/bool.hpp>
31-
# include <boost/mpl/not.hpp>
32-
# include <boost/mpl/or.hpp>
33-
3423
# include <boost/python/object/select_holder.hpp>
3524
# include <boost/python/object/class_wrapper.hpp>
3625
# include <boost/python/object/make_instance.hpp>
@@ -44,6 +33,18 @@
4433
# include <boost/python/detail/def_helper.hpp>
4534
# include <boost/python/detail/force_instantiate.hpp>
4635

36+
# include <boost/type_traits/is_same.hpp>
37+
# include <boost/type_traits/is_convertible.hpp>
38+
# include <boost/type_traits/is_member_function_pointer.hpp>
39+
# include <boost/type_traits/is_polymorphic.hpp>
40+
41+
# include <boost/mpl/size.hpp>
42+
# include <boost/mpl/for_each.hpp>
43+
# include <boost/mpl/bool.hpp>
44+
# include <boost/mpl/not.hpp>
45+
# include <boost/mpl/or.hpp>
46+
# include <boost/mpl/vector/vector10.hpp>
47+
4748
# include <boost/utility.hpp>
4849
# include <boost/detail/workaround.hpp>
4950

@@ -106,6 +107,27 @@ namespace detail
106107
SelectHolder::register_();
107108
}
108109

110+
//
111+
// register_wrapper_class -- register the relationship between a
112+
// virtual function callback wrapper class and the class being
113+
// wrapped.
114+
//
115+
template <class T>
116+
inline void register_wrapper_class(T*, T*, int) {}
117+
118+
template <class Wrapper, class T>
119+
inline void register_wrapper_class(Wrapper*, T*, ...)
120+
{
121+
objects::register_class_from_python<Wrapper, mpl::vector1<T> >();
122+
objects::copy_class_object(type_id<T>(), type_id<Wrapper>());
123+
}
124+
125+
template <class Held, class T>
126+
inline void register_wrapper_class(Held* = 0, T* = 0)
127+
{
128+
register_wrapper_class((Held*)0, (T*)0, 0);
129+
}
130+
109131
# ifdef BOOST_PYTHON_NO_MEMBER_POINTER_ORDERING
110132
template <class T>
111133
struct is_data_member_pointer
@@ -562,6 +584,12 @@ inline void class_<T,X1,X2,X3>::register_() const
562584
{
563585
objects::register_class_from_python<T,bases>();
564586

587+
typedef BOOST_DEDUCED_TYPENAME holder_selector::type select_holder;
588+
typedef BOOST_DEDUCED_TYPENAME select_holder::type holder;
589+
typedef BOOST_DEDUCED_TYPENAME holder::held_type held_t;
590+
591+
detail::register_wrapper_class<held_t,T>();
592+
565593
detail::register_class_to_python<T>(
566594
mpl::bool_<is_copyable>()
567595
# if BOOST_WORKAROUND(__MWERKS__, <= 0x2407)

include/boost/python/object/class.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ struct BOOST_PYTHON_DECL class_base : python::api::object
5858
void make_method_static(const char *method_name);
5959
};
6060

61+
BOOST_PYTHON_DECL void copy_class_object(type_info const& src, type_info const& dst);
62+
6163
}}} // namespace boost::python::objects
6264

6365
#endif // CLASS_DWA20011214_HPP

include/boost/python/object/pointer_holder.hpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ bool is_null(T* p, int)
5252
template <class Pointer, class Value>
5353
struct pointer_holder : instance_holder
5454
{
55+
typedef Value held_type;
5556
typedef Value value_type;
5657

5758
pointer_holder(Pointer);
@@ -73,9 +74,7 @@ struct pointer_holder : instance_holder
7374
template <class Pointer, class Value>
7475
struct pointer_holder_back_reference : instance_holder
7576
{
76-
private:
7777
typedef typename python::pointee<Pointer>::type held_type;
78-
public:
7978
typedef Value value_type;
8079

8180
// Not sure about this one -- can it work? The source object

include/boost/python/object/value_holder.hpp

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,11 @@ namespace boost { namespace python { namespace objects {
3737
# define BOOST_PYTHON_UNFORWARD_LOCAL(z, n, _) BOOST_PP_COMMA_IF(n) objects::do_unforward(a##n,0)
3838
# endif
3939

40-
template <class Held>
40+
template <class Value>
4141
struct value_holder : instance_holder
4242
{
43-
typedef Held value_type;
43+
typedef Value held_type;
44+
typedef Value value_type;
4445

4546
// Forward construction to the held object
4647
# define BOOST_PP_ITERATION_PARAMS_1 (4, (0, BOOST_PYTHON_MAX_ARITY, <boost/python/object/value_holder.hpp>, 1))
@@ -50,13 +51,14 @@ struct value_holder : instance_holder
5051
void* holds(type_info);
5152

5253
private: // data members
53-
Held m_held;
54+
Value m_held;
5455
};
5556

56-
template <class Held, class BackReferenceType>
57+
template <class Value, class Held>
5758
struct value_holder_back_reference : instance_holder
5859
{
59-
typedef Held value_type;
60+
typedef Held held_type;
61+
typedef Value value_type;
6062

6163
// Forward construction to the held object
6264
# define BOOST_PP_ITERATION_PARAMS_1 (4, (0, BOOST_PYTHON_MAX_ARITY, <boost/python/object/value_holder.hpp>, 2))
@@ -66,29 +68,29 @@ struct value_holder_back_reference : instance_holder
6668
void* holds(type_info);
6769

6870
private: // data members
69-
BackReferenceType m_held;
71+
Held m_held;
7072
};
7173

7274
# undef BOOST_PYTHON_UNFORWARD_LOCAL
7375

74-
template <class Held>
75-
void* value_holder<Held>::holds(type_info dst_t)
76+
template <class Value>
77+
void* value_holder<Value>::holds(type_info dst_t)
7678
{
77-
type_info src_t = python::type_id<Held>();
79+
type_info src_t = python::type_id<Value>();
7880
return src_t == dst_t ? &m_held
7981
: find_static_type(&m_held, src_t, dst_t);
8082
}
8183

82-
template <class Held, class BackReferenceType>
83-
void* value_holder_back_reference<Held,BackReferenceType>::holds(
84+
template <class Value, class Held>
85+
void* value_holder_back_reference<Value,Held>::holds(
8486
type_info dst_t)
8587
{
86-
type_info src_t = python::type_id<Held>();
87-
Held* x = &m_held;
88+
type_info src_t = python::type_id<Value>();
89+
Value* x = &m_held;
8890

8991
if (dst_t == src_t)
9092
return x;
91-
else if (dst_t == python::type_id<BackReferenceType>())
93+
else if (dst_t == python::type_id<Held>())
9294
return &m_held;
9395
else
9496
return find_static_type(x, src_t, dst_t);

src/object/class.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,16 @@ namespace objects
521521
converters.m_class_object = (PyTypeObject*)incref(this->ptr());
522522
}
523523

524+
BOOST_PYTHON_DECL void copy_class_object(type_info const& src, type_info const& dst)
525+
{
526+
converter::registration& dst_converters
527+
= const_cast<converter::registration&>(converter::registry::lookup(dst));
528+
529+
converter::registration const& src_converters = converter::registry::lookup(src);
530+
531+
dst_converters.m_class_object = src_converters.m_class_object;
532+
}
533+
524534
void class_base::set_instance_size(std::size_t instance_size)
525535
{
526536
this->attr("__instance_size__") = instance_size;

test/polymorphism.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,28 @@ struct C : A
5252
virtual std::string f() { return "C::f()"; }
5353
};
5454

55+
struct D : A
56+
{
57+
virtual std::string f() { return "D::f()"; }
58+
std::string g() { return "D::g()"; }
59+
};
60+
61+
struct DCallback : D, Callback
62+
{
63+
DCallback (PyObject* self) : Callback(self) {}
64+
65+
std::string f()
66+
{
67+
return call_method<std::string>(mSelf, "f");
68+
}
69+
70+
std::string default_f()
71+
{
72+
return A::f();
73+
}
74+
};
75+
76+
5577
A& getBCppObj ()
5678
{
5779
static B b;
@@ -79,6 +101,8 @@ C& getCCppObj ()
79101
return c;
80102
}
81103

104+
A* pass_a(A* x) { return x; }
105+
82106
BOOST_PYTHON_MODULE_INIT(polymorphism_ext)
83107
{
84108
class_<A,boost::noncopyable,ACallback>("A")
@@ -91,6 +115,13 @@ BOOST_PYTHON_MODULE_INIT(polymorphism_ext)
91115
.def("f", &C::f)
92116
;
93117

118+
class_<D,bases<A>,DCallback,boost::noncopyable>("D")
119+
.def("f", &D::f, &DCallback::default_f)
120+
.def("g", &D::g)
121+
;
122+
123+
def("pass_a", &pass_a, return_internal_reference<>());
124+
94125
def("getCCppObj", getCCppObj, return_value_policy<reference_existing_object>());
95126

96127
def("factory", factory, return_value_policy<manage_new_object>());

test/polymorphism.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,21 @@ def test_factory(self):
3232
self.failUnlessEqual(type(factory(1)), A)
3333
self.failUnlessEqual(type(factory(2)), C)
3434

35-
def testReturnPy(self):
35+
def test_return_py(self):
3636

37-
class D(A):
37+
class X(A):
3838
def f(self):
39-
return 'D.f'
39+
return 'X.f'
4040

41-
d = D()
41+
x = X()
4242

43-
self.failUnlessEqual ('D.f', d.f())
44-
self.failUnlessEqual ('D.f', call_f(d))
43+
self.failUnlessEqual ('X.f', x.f())
44+
self.failUnlessEqual ('X.f', call_f(x))
4545

46+
def test_wrapper_downcast(self):
47+
a = pass_a(D())
48+
self.failUnlessEqual('D::g()', a.g())
49+
4650
if __name__ == "__main__":
4751

4852
# remove the option which upsets unittest

0 commit comments

Comments
 (0)