Skip to content

Commit bcaa104

Browse files
committed
More smart pointer handling
[SVN r15069]
1 parent 0b33d18 commit bcaa104

File tree

7 files changed

+97
-27
lines changed

7 files changed

+97
-27
lines changed

include/boost/python/class.hpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,17 @@ namespace detail
5252
// to the type of holder that must be created. The 3rd argument is a
5353
// reference to the Python type object to be created.
5454
template <class T, class Holder>
55-
static inline void register_copy_constructor(mpl::bool_t<true> const&, Holder*, object const& obj, T* = 0)
55+
static inline void register_copy_constructor(mpl::bool_t<true> const&, Holder*, T* = 0)
5656
{
57-
objects::class_wrapper<T,Holder> x(obj);
57+
force_instantiate(objects::class_wrapper<T,Holder>());
58+
Holder::register_();
5859
}
5960

6061
// Tag dispatched to have no effect.
6162
template <class T, class Holder>
62-
static inline void register_copy_constructor(mpl::bool_t<false> const&, Holder*, object const&, T* = 0)
63+
static inline void register_copy_constructor(mpl::bool_t<false> const&, Holder*, T* = 0)
6364
{
65+
Holder::register_();
6466
}
6567

6668
template <class T> int assert_default_constructible(T const&);
@@ -331,7 +333,7 @@ inline void class_<T,X1,X2,X3>::register_() const
331333
detail::register_copy_constructor<T>(
332334
mpl::bool_t<is_copyable>()
333335
, objects::select_holder<T,held_type>((held_type*)0).get()
334-
, *this);
336+
);
335337
}
336338

337339

include/boost/python/instance_holder.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ struct BOOST_PYTHON_DECL instance_holder : private noncopyable
2424
virtual void* holds(type_info) = 0;
2525

2626
void install(PyObject* inst) throw();
27+
28+
// Register any converters associated with this Holder
29+
static inline void register_() {}
30+
2731
private:
2832
instance_holder* m_next;
2933
};

include/boost/python/object/class_wrapper.hpp

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,37 @@
88

99
# include <boost/python/handle.hpp>
1010
# include <boost/python/to_python_converter.hpp>
11+
# include <boost/python/converter/registered.hpp>
12+
# include <boost/ref.hpp>
1113

1214
namespace boost { namespace python { namespace objects {
1315

14-
template <class T, class Holder>
15-
struct class_wrapper
16-
: to_python_converter<T,class_wrapper<T,Holder> >
16+
template <class Src, class Holder>
17+
struct copy_construct_instance
1718
{
18-
class_wrapper(object const& type_)
19-
: m_class_object_keeper(type_)
19+
static Holder* execute(PyObject* instance, Src const& x)
2020
{
21-
assert(type_.ptr()->ob_type == (PyTypeObject*)class_metatype().get());
22-
m_class_object = (PyTypeObject*)type_.ptr();
21+
return new Holder(instance, cref(x));
2322
}
24-
25-
static PyObject* convert(T const& x)
23+
};
24+
25+
// Used to convert objects of type Src to wrapped C++ classes by
26+
// building a new instance object and installing a Holder constructed
27+
// from the Src object.
28+
template <class Src, class Holder, class MakeHolder = copy_construct_instance<Src,Holder> >
29+
struct class_wrapper
30+
: to_python_converter<Src,class_wrapper<Src,Holder,MakeHolder> >
31+
{
32+
static PyObject* convert(Src const& x)
2633
{
34+
// Get the class object associated with the wrapped type
35+
typedef typename Holder::value_type value_type;
36+
PyTypeObject* class_object = converter::registered<value_type>::converters.class_object;
37+
2738
// Don't call the type directly to do the construction, since
2839
// that would require the registration of an appropriate
2940
// __init__ function.
30-
PyObject* raw_result = m_class_object->tp_alloc(m_class_object, 0);
41+
PyObject* raw_result = class_object->tp_alloc(class_object, 0);
3142

3243
if (raw_result == 0)
3344
return 0;
@@ -38,23 +49,16 @@ struct class_wrapper
3849

3950
// Build a value_holder to contain the object using the copy
4051
// constructor
41-
Holder* p = new Holder(raw_result, cref(x));
52+
Holder* p = MakeHolder::execute(raw_result, x);
4253

4354
// Install it in the instance
4455
p->install(raw_result);
4556

4657
// Return the new result
4758
return result.release();
4859
}
49-
50-
private:
51-
object m_class_object_keeper;
52-
static PyTypeObject* m_class_object;
5360
};
5461

55-
template <class T, class Holder>
56-
PyTypeObject* class_wrapper<T,Holder>::m_class_object;
57-
5862
}}} // namespace boost::python::objects
5963

6064
#endif // CLASS_WRAPPER_DWA20011221_HPP

include/boost/python/object/pointer_holder.hpp

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
# include <boost/python/object/inheritance.hpp>
1717
# include <boost/python/object/find_instance.hpp>
1818
# include <boost/python/object/forward.hpp>
19+
# include <boost/python/object/class_wrapper.hpp>
1920
# include <boost/python/pointee.hpp>
2021
# include <boost/python/detail/force_instantiate.hpp>
2122
# include <boost/python/detail/preprocessor.hpp>
@@ -34,13 +35,26 @@ namespace boost { namespace python { namespace objects {
3435
template <class Pointer, class Value>
3536
struct pointer_holder : instance_holder
3637
{
38+
typedef Value value_type;
39+
3740
pointer_holder(Pointer);
3841

42+
static void register_();
43+
3944
// Forward construction to the held object
4045

4146
# define BOOST_PP_ITERATION_PARAMS_1 (4, (0, BOOST_PYTHON_MAX_ARITY, <boost/python/object/pointer_holder.hpp>, 1))
4247
# include BOOST_PP_ITERATE()
4348

49+
private: // types
50+
struct construct_from_pointer
51+
{
52+
static pointer_holder* execute(PyObject*, Pointer x)
53+
{
54+
return new pointer_holder(x);
55+
}
56+
};
57+
4458
private: // required holder implementation
4559
void* holds(type_info);
4660

@@ -54,9 +68,14 @@ struct pointer_holder_back_reference : instance_holder
5468
private:
5569
typedef typename python::pointee<Pointer>::type held_type;
5670
public:
71+
typedef Value value_type;
5772

73+
// Not sure about this one -- can it work? The source object
74+
// undoubtedly does not carry the correct back reference pointer.
5875
pointer_holder_back_reference(Pointer);
5976

77+
static void register_();
78+
6079
// Forward construction to the held object
6180
# define BOOST_PP_ITERATION_PARAMS_1 (4, (0, BOOST_PYTHON_MAX_ARITY, <boost/python/object/pointer_holder.hpp>, 2))
6281
# include BOOST_PP_ITERATE()
@@ -76,12 +95,29 @@ inline pointer_holder<Pointer,Value>::pointer_holder(Pointer p)
7695
{
7796
}
7897

98+
template <class Pointer, class Value>
99+
inline void pointer_holder<Pointer,Value>::register_()
100+
{
101+
python::detail::force_instantiate(class_wrapper<Pointer,pointer_holder,construct_from_pointer>());
102+
python::detail::force_instantiate(instance_finder<Pointer>::registration);
103+
}
104+
105+
79106
template <class Pointer, class Value>
80107
inline pointer_holder_back_reference<Pointer,Value>::pointer_holder_back_reference(Pointer p)
81108
: m_p(p)
82109
{
83110
}
84111

112+
template <class Pointer, class Value>
113+
inline void pointer_holder_back_reference<Pointer,Value>::register_()
114+
{
115+
// not implemented at least until we solve the back reference issue mentioned above.
116+
// python::detail::force_instantiate(class_wrapper<Pointer,pointer_holder_back_reference>());
117+
python::detail::force_instantiate(instance_finder<Pointer>::registration);
118+
python::detail::force_instantiate(instance_finder<held_type>::registration);
119+
}
120+
85121
template <class Pointer, class Value>
86122
void* pointer_holder<Pointer, Value>::holds(type_info dst_t)
87123
{
@@ -142,9 +178,7 @@ void* pointer_holder_back_reference<Pointer, Value>::holds(type_info dst_t)
142178
: m_p(new held_type(
143179
p BOOST_PP_COMMA_IF(N) BOOST_PP_REPEAT(N, BOOST_PYTHON_UNFORWARD_LOCAL, nil)
144180
))
145-
{
146-
python::detail::force_instantiate(instance_finder<held_type>::registration);
147-
}
181+
{}
148182

149183
# undef N
150184

include/boost/python/object/value_holder.hpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ namespace boost { namespace python { namespace objects {
2929
template <class Held>
3030
struct value_holder : instance_holder
3131
{
32+
typedef Held value_type;
33+
3234
// Forward construction to the held object
3335
# define BOOST_PP_ITERATION_PARAMS_1 (4, (0, BOOST_PYTHON_MAX_ARITY, <boost/python/object/value_holder.hpp>, 1))
3436
# include BOOST_PP_ITERATE()
@@ -43,6 +45,10 @@ struct value_holder : instance_holder
4345
template <class Held, class BackReferenceType>
4446
struct value_holder_back_reference : instance_holder
4547
{
48+
typedef Held value_type;
49+
50+
static void register_();
51+
4652
// Forward construction to the held object
4753
# define BOOST_PP_ITERATION_PARAMS_1 (4, (0, BOOST_PYTHON_MAX_ARITY, <boost/python/object/value_holder.hpp>, 2))
4854
# include BOOST_PP_ITERATE()
@@ -79,6 +85,12 @@ void* value_holder_back_reference<Held,BackReferenceType>::holds(
7985
return find_static_type(x, src_t, dst_t);
8086
}
8187

88+
template <class Held, class BackReferenceType>
89+
void value_holder_back_reference<Held,BackReferenceType>::register_()
90+
{
91+
python::detail::force_instantiate(instance_finder<BackReferenceType>::registration);
92+
}
93+
8294
}}} // namespace boost::python::objects
8395

8496
# endif // VALUE_HOLDER_DWA20011215_HPP
@@ -119,7 +131,6 @@ void* value_holder_back_reference<Held,BackReferenceType>::holds(
119131
BOOST_PP_REPEAT(N, BOOST_PYTHON_UNFORWARD_LOCAL, nil)
120132
)
121133
{
122-
python::detail::force_instantiate(instance_finder<BackReferenceType>::registration);
123134
}
124135

125136
# undef N

test/m1.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,11 @@ A take_a(A const& a) { return a; }
190190
B take_b(B& b) { return b; }
191191
C take_c(C* c) { return *c; }
192192
D take_d(D* const& d) { return *d; }
193-
193+
194+
D take_d_shared_ptr(boost::shared_ptr<D> d) { return *d; }
195+
196+
boost::shared_ptr<A> d_factory() { return boost::shared_ptr<B>(new D); }
197+
194198
BOOST_PYTHON_MODULE_INIT(m1)
195199
{
196200
using namespace boost::python;
@@ -237,6 +241,10 @@ BOOST_PYTHON_MODULE_INIT(m1)
237241
.def("take_b", take_b)
238242
.def("take_c", take_c)
239243
.def("take_d", take_d)
244+
245+
246+
.def("take_d_shared_ptr", take_d_shared_ptr)
247+
.def("d_factory", d_factory)
240248
;
241249

242250
class_<A, shared_ptr<A> >("A")

test/newtest.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,13 @@
158158
>>> take_d(d).name()
159159
'D'
160160
161+
>>> take_d_shared_ptr(d).name()
162+
'D'
163+
164+
>>> d_as_a = d_factory()
165+
>>> dd = take_d(d_as_a)
166+
>>> dd.name()
167+
'D'
161168
162169
"""
163170

0 commit comments

Comments
 (0)