Skip to content

Commit 82563df

Browse files
committed
Better support for rvalue from-python conversions of shared_ptr:
always return a pointer that holds the owning python object *unless* the python object contains a NULL shared_ptr holder of the right type. [SVN r28947]
1 parent adb7b62 commit 82563df

File tree

13 files changed

+186
-26
lines changed

13 files changed

+186
-26
lines changed

include/boost/python/converter/registered.hpp

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,16 @@
1010
# include <boost/type_traits/transform_traits.hpp>
1111
# include <boost/type_traits/cv_traits.hpp>
1212
# include <boost/detail/workaround.hpp>
13+
# include <boost/type.hpp>
1314

14-
namespace boost { namespace python { namespace converter {
15+
namespace boost {
16+
17+
// You'll see shared_ptr mentioned in this header because we need to
18+
// note which types are shared_ptrs in their registrations, to
19+
// implement special shared_ptr handling for rvalue conversions.
20+
template <class T> class shared_ptr;
21+
22+
namespace python { namespace converter {
1523

1624
struct registration;
1725

@@ -26,9 +34,9 @@ namespace detail
2634

2735
template <class T>
2836
struct registered
29-
: detail::registered_base<
37+
: detail::registered_base<
3038
typename add_reference<
31-
typename add_cv<T>::type
39+
typename add_cv<T>::type
3240
>::type
3341
>
3442
{
@@ -50,10 +58,52 @@ struct registered<T&>
5058
//
5159
namespace detail
5260
{
61+
inline void
62+
register_shared_ptr(...)
63+
{
64+
}
65+
66+
template <class T>
67+
inline void
68+
register_shared_ptr(type<shared_ptr<T> >)
69+
{
70+
registry::lookup_shared_ptr(type_id<shared_ptr<T> >());
71+
}
72+
73+
template <class T>
74+
inline void
75+
register_shared_ptr(type<shared_ptr<T> const>)
76+
{
77+
detail::register_shared_ptr(type<shared_ptr<T> >());
78+
}
79+
80+
template <class T>
81+
inline void
82+
register_shared_ptr(type<shared_ptr<T> volatile>)
83+
{
84+
detail::register_shared_ptr(type<shared_ptr<T> >());
85+
}
86+
87+
template <class T>
88+
inline void
89+
register_shared_ptr(type<shared_ptr<T> const volatile>)
90+
{
91+
detail::register_shared_ptr(type<shared_ptr<T> >());
92+
}
93+
94+
template <class T>
95+
registration const&
96+
registry_lookup(type<T&>)
97+
{
98+
detail::register_shared_ptr(type<T>());
99+
return registry::lookup(type_id<T>());
100+
}
101+
53102
template <class T>
54103
registration const& registered_base<T>::converters
55-
= registry::lookup(type_id<T>());
104+
= detail::registry_lookup(type<T>());
56105
}
106+
57107
}}} // namespace boost::python::converter
58108

59109
#endif // REGISTERED_DWA2002710_HPP

include/boost/python/converter/registrations.hpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ struct rvalue_from_python_chain
3333
struct BOOST_PYTHON_DECL registration
3434
{
3535
public: // member functions
36-
explicit registration(type_info);
36+
explicit registration(type_info target, bool is_shared_ptr = false);
3737

3838
// Convert the appropriately-typed data to Python
3939
PyObject* to_python(void const volatile*) const;
@@ -56,7 +56,11 @@ struct BOOST_PYTHON_DECL registration
5656

5757
// The unique to_python converter for the associated C++ type.
5858
to_python_function_t m_to_python;
59-
59+
60+
// True iff this type is a shared_ptr. Needed for special rvalue
61+
// from_python handling.
62+
const bool is_shared_ptr;
63+
6064
# if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3003))
6165
private:
6266
void operator=(registration); // This is not defined, and just keeps MWCW happy.
@@ -66,12 +70,13 @@ struct BOOST_PYTHON_DECL registration
6670
//
6771
// implementations
6872
//
69-
inline registration::registration(type_info target_type)
73+
inline registration::registration(type_info target_type, bool is_shared_ptr)
7074
: target_type(target_type)
7175
, lvalue_chain(0)
7276
, rvalue_chain(0)
7377
, m_class_object(0)
7478
, m_to_python(0)
79+
, is_shared_ptr(is_shared_ptr)
7580
{}
7681

7782
inline bool operator<(registration const& lhs, registration const& rhs)

include/boost/python/converter/registry.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ namespace registry
2020
// Get the registration corresponding to the type, creating it if necessary
2121
BOOST_PYTHON_DECL registration const& lookup(type_info);
2222

23+
// Get the registration corresponding to the type, creating it if
24+
// necessary. Use this first when the type is a shared_ptr.
25+
BOOST_PYTHON_DECL registration const& lookup_shared_ptr(type_info);
26+
2327
// Return a pointer to the corresponding registration, if one exists
2428
BOOST_PYTHON_DECL registration const* query(type_info);
2529

include/boost/python/instance_holder.hpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,13 @@ struct BOOST_PYTHON_DECL instance_holder : private noncopyable
2323
// return the next holder in a chain
2424
instance_holder* next() const;
2525

26-
virtual void* holds(type_info) = 0;
26+
// When the derived holder actually holds by [smart] pointer and
27+
// null_ptr_only is set, only report that the type is held when
28+
// the pointer is null. This is needed for proper shared_ptr
29+
// support, to prevent holding shared_ptrs from being found when
30+
// converting from python so that we can use the conversion method
31+
// that always holds the Python object.
32+
virtual void* holds(type_info, bool null_ptr_only) = 0;
2733

2834
void install(PyObject* inst) throw();
2935

include/boost/python/object/find_instance.hpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@
1010
namespace boost { namespace python { namespace objects {
1111

1212
// Given a type_id, find the instance data which corresponds to it, or
13-
// return 0 in case no such type is held.
14-
BOOST_PYTHON_DECL void* find_instance_impl(PyObject*, type_info);
13+
// return 0 in case no such type is held. If null_shared_ptr_only is
14+
// true and the type being sought is a shared_ptr, only find an
15+
// instance if it turns out to be NULL. Needed for shared_ptr rvalue
16+
// from_python support.
17+
BOOST_PYTHON_DECL void* find_instance_impl(PyObject*, type_info, bool null_shared_ptr_only = false);
1518

1619
}}} // namespace boost::python::objects
1720

include/boost/python/object/pointer_holder.hpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ struct pointer_holder : instance_holder
6565
private: // types
6666

6767
private: // required holder implementation
68-
void* holds(type_info);
68+
void* holds(type_info, bool null_ptr_only);
6969

7070
template <class T>
7171
inline void* holds_wrapped(type_info dst_t, wrapper<T>*,T* p)
@@ -99,7 +99,7 @@ struct pointer_holder_back_reference : instance_holder
9999
# include BOOST_PP_ITERATE()
100100

101101
private: // required holder implementation
102-
void* holds(type_info);
102+
void* holds(type_info, bool null_ptr_only);
103103

104104
private: // data members
105105
Pointer m_p;
@@ -120,9 +120,11 @@ inline pointer_holder_back_reference<Pointer,Value>::pointer_holder_back_referen
120120
}
121121

122122
template <class Pointer, class Value>
123-
void* pointer_holder<Pointer, Value>::holds(type_info dst_t)
123+
void* pointer_holder<Pointer, Value>::holds(type_info dst_t, bool null_ptr_only)
124124
{
125-
if (dst_t == python::type_id<Pointer>())
125+
if (dst_t == python::type_id<Pointer>()
126+
&& !(null_ptr_only && get_pointer(this->m_p))
127+
)
126128
return &this->m_p;
127129

128130
Value* p = get_pointer(this->m_p);
@@ -137,10 +139,12 @@ void* pointer_holder<Pointer, Value>::holds(type_info dst_t)
137139
}
138140

139141
template <class Pointer, class Value>
140-
void* pointer_holder_back_reference<Pointer, Value>::holds(type_info dst_t)
142+
void* pointer_holder_back_reference<Pointer, Value>::holds(type_info dst_t, bool null_ptr_only)
141143
{
142-
if (dst_t == python::type_id<Pointer>())
143-
return &this->m_p;
144+
if (dst_t == python::type_id<Pointer>()
145+
&& !(null_ptr_only && get_pointer(this->m_p))
146+
)
147+
return &this->m_p;
144148

145149
if (!get_pointer(this->m_p))
146150
return 0;

include/boost/python/object/value_holder.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ struct value_holder : instance_holder
4848
# include BOOST_PP_ITERATE()
4949

5050
private: // required holder implementation
51-
void* holds(type_info);
51+
void* holds(type_info, bool null_ptr_only);
5252

5353
template <class T>
5454
inline void* holds_wrapped(type_info dst_t, wrapper<T>*,T* p)
@@ -75,7 +75,7 @@ struct value_holder_back_reference : instance_holder
7575
# include BOOST_PP_ITERATE()
7676

7777
private: // required holder implementation
78-
void* holds(type_info);
78+
void* holds(type_info, bool null_ptr_only);
7979

8080
private: // data members
8181
Held m_held;
@@ -84,7 +84,7 @@ struct value_holder_back_reference : instance_holder
8484
# undef BOOST_PYTHON_UNFORWARD_LOCAL
8585

8686
template <class Value>
87-
void* value_holder<Value>::holds(type_info dst_t)
87+
void* value_holder<Value>::holds(type_info dst_t, bool null_ptr_only)
8888
{
8989
if (void* wrapped = holds_wrapped(dst_t, &m_held, &m_held))
9090
return wrapped;
@@ -96,7 +96,7 @@ void* value_holder<Value>::holds(type_info dst_t)
9696

9797
template <class Value, class Held>
9898
void* value_holder_back_reference<Value,Held>::holds(
99-
type_info dst_t)
99+
type_info dst_t, bool null_ptr_only)
100100
{
101101
type_info src_t = python::type_id<Value>();
102102
Value* x = &m_held;

src/converter/from_python.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ BOOST_PYTHON_DECL rvalue_from_python_stage1_data rvalue_from_python_stage1(
4343

4444
// First check to see if it's embedded in an extension class
4545
// instance, as a special case.
46-
data.convertible = objects::find_instance_impl(source, converters.target_type);
46+
data.convertible = objects::find_instance_impl(source, converters.target_type, converters.is_shared_ptr);
4747
if (data.convertible)
4848
{
4949
data.construct = 0;

src/converter/registry.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ namespace // <unnamed>
128128
}
129129
#endif // BOOST_PYTHON_CONVERTER_REGISTRY_APPLE_MACH_WORKAROUND
130130

131-
entry* get(type_info type)
131+
entry* get(type_info type, bool is_shared_ptr = false)
132132
{
133133
# ifdef BOOST_PYTHON_TRACE_REGISTRY
134134
registry_t::iterator p = entries().find(entry(type));
@@ -138,7 +138,7 @@ namespace // <unnamed>
138138
? "...NOT found\n" : "...found\n");
139139
# endif
140140
std::pair<registry_t::const_iterator,bool> pos_ins
141-
= entries().insert(entry(type));
141+
= entries().insert(entry(type,is_shared_ptr));
142142

143143
# if __MWERKS__ >= 0x3000
144144
// do a little invariant checking if a change was made
@@ -230,6 +230,11 @@ namespace registry
230230
return *get(key);
231231
}
232232

233+
registration const& lookup_shared_ptr(type_info key)
234+
{
235+
return *get(key, true);
236+
}
237+
233238
registration const* query(type_info type)
234239
{
235240
registry_t::iterator p = entries().find(entry(type));

src/object/class.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ namespace objects
407407
}
408408

409409
BOOST_PYTHON_DECL void*
410-
find_instance_impl(PyObject* inst, type_info type)
410+
find_instance_impl(PyObject* inst, type_info type, bool null_shared_ptr_only)
411411
{
412412
if (inst->ob_type->ob_type != &class_metatype_object)
413413
return 0;
@@ -416,7 +416,7 @@ namespace objects
416416

417417
for (instance_holder* match = self->objects; match != 0; match = match->next())
418418
{
419-
void* const found = match->holds(type);
419+
void* const found = match->holds(type, null_shared_ptr_only);
420420
if (found)
421421
return found;
422422
}

0 commit comments

Comments
 (0)