Skip to content

Commit 3286979

Browse files
committed
automatic shared_ptr from_python conversions
[SVN r16467]
1 parent 3c19b89 commit 3286979

15 files changed

Lines changed: 355 additions & 63 deletions

include/boost/python/class.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ namespace detail
8585
static inline void register_copy_constructor(mpl::bool_c<true> const&, SelectHolder const& , T* = 0)
8686
{
8787
typedef typename SelectHolder::type holder;
88-
force_instantiate(objects::class_wrapper<T,holder, objects::make_instance<T,holder> >());
88+
force_instantiate(objects::class_cref_wrapper<T, objects::make_instance<T,holder> >());
8989
SelectHolder::register_();
9090
}
9191

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright David Abrahams 2002. Permission to copy, use,
2+
// modify, sell and distribute this software is granted provided this
3+
// copyright notice appears in all copies. This software is provided
4+
// "as is" without express or implied warranty, and with no claim as
5+
// to its suitability for any purpose.
6+
#ifndef AS_TO_PYTHON_FUNCTION_DWA2002121_HPP
7+
# define AS_TO_PYTHON_FUNCTION_DWA2002121_HPP
8+
# include <boost/python/converter/to_python_function_type.hpp>
9+
10+
namespace boost { namespace python { namespace converter {
11+
12+
// Given a typesafe to_python conversion function, produces a
13+
// to_python_function_t which can be registered in the usual way.
14+
template <class T, class ToPython>
15+
struct as_to_python_function
16+
{
17+
// Assertion functions used to prevent wrapping of converters
18+
// which take non-const reference parameters. The T* argument in
19+
// the first overload ensures it isn't used in case T is a
20+
// reference.
21+
template <class U>
22+
static int convert_function_must_take_value_or_const_reference(U(*)(T), int, T* = 0);
23+
template <class U>
24+
static int convert_function_must_take_value_or_const_reference(U(*)(T const&), long ...);
25+
26+
static PyObject* convert(void const* x)
27+
{
28+
BOOST_STATIC_ASSERT(
29+
sizeof(
30+
convert_function_must_take_value_or_const_reference(&ToPython::convert, 1L))
31+
== sizeof(int));
32+
33+
// Yes, the const_cast below opens a hole in const-correctness,
34+
// but it's needed to convert auto_ptr<U> to python.
35+
//
36+
// How big a hole is it? It allows ToPython::convert() to be
37+
// a function which modifies its argument. The upshot is that
38+
// client converters applied to const objects may invoke
39+
// undefined behavior. The damage, however, is limited by the
40+
// use of the assertion function. Thus, the only way this can
41+
// modify its argument is if T is an auto_ptr-like type. There
42+
// is still a const-correctness hole w.r.t. auto_ptr<U> const,
43+
// but c'est la vie.
44+
return ToPython::convert(*const_cast<T*>(static_cast<T const*>(x)));
45+
}
46+
};
47+
48+
}}} // namespace boost::python::converter
49+
50+
#endif // AS_TO_PYTHON_FUNCTION_DWA2002121_HPP
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright David Abrahams 2002. Permission to copy, use,
2+
// modify, sell and distribute this software is granted provided this
3+
// copyright notice appears in all copies. This software is provided
4+
// "as is" without express or implied warranty, and with no claim as
5+
// to its suitability for any purpose.
6+
#ifndef SHARED_PTR_FROM_PYTHON_DWA20021130_HPP
7+
# define SHARED_PTR_FROM_PYTHON_DWA20021130_HPP
8+
9+
# include <boost/python/handle.hpp>
10+
# include <boost/python/converter/shared_ptr_deleter.hpp>
11+
12+
namespace boost { namespace python { namespace converter {
13+
14+
template <class T>
15+
struct shared_ptr_from_python
16+
{
17+
shared_ptr_from_python()
18+
{
19+
converter::registry::insert(&convertible, &construct, type_id<shared_ptr<T> >());
20+
}
21+
22+
static shared_ptr_from_python const registration;
23+
private:
24+
static void* convertible(PyObject* p)
25+
{
26+
return p == Py_None
27+
? p
28+
: converter::get_lvalue_from_python(p, registered<T>::converters)
29+
;
30+
}
31+
32+
static void construct(PyObject* source, rvalue_from_python_stage1_data* data)
33+
{
34+
void* const storage = ((converter::rvalue_from_python_storage<shared_ptr<T> >*)data)->storage.bytes;
35+
// Deal with the "None" case.
36+
if (data->convertible == source)
37+
new (storage) shared_ptr<T>();
38+
else
39+
new (storage) shared_ptr<T>(
40+
static_cast<T*>(data->convertible),
41+
shared_ptr_deleter(handle<>(borrowed(source)))
42+
);
43+
44+
data->convertible = storage;
45+
}
46+
};
47+
48+
template <class T>
49+
shared_ptr_from_python<T> const shared_ptr_from_python<T>::registration;
50+
51+
}}} // namespace boost::python::converter
52+
53+
#endif // SHARED_PTR_FROM_PYTHON_DWA20021130_HPP

include/boost/python/converter/to_python_function_type.hpp

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -15,43 +15,6 @@ namespace boost { namespace python { namespace converter {
1515
// type-safety is preserved through runtime registration.
1616
typedef PyObject* (*to_python_function_t)(void const*);
1717

18-
// Given a typesafe to_python conversion function, produces a
19-
// to_python_function_t which can be registered in the usual way.
20-
template <class T, class ToPython>
21-
struct as_to_python_function
22-
{
23-
// Assertion functions used to prevent wrapping of converters
24-
// which take non-const reference parameters. The T* argument in
25-
// the first overload ensures it isn't used in case T is a
26-
// reference.
27-
template <class U>
28-
static int convert_function_must_take_value_or_const_reference(U(*)(T), int, T* = 0);
29-
template <class U>
30-
static int convert_function_must_take_value_or_const_reference(U(*)(T const&), long ...);
31-
32-
static PyObject* convert(void const* x)
33-
{
34-
35-
BOOST_STATIC_ASSERT(
36-
sizeof(
37-
convert_function_must_take_value_or_const_reference(&ToPython::convert, 1L))
38-
== sizeof(int));
39-
40-
// Yes, the const_cast below opens a hole in const-correctness,
41-
// but it's needed to convert auto_ptr<U> to python.
42-
//
43-
// How big a hole is it? It allows ToPython::convert() to be
44-
// a function which modifies its argument. The upshot is that
45-
// client converters applied to const objects may invoke
46-
// undefined behavior. The damage, however, is limited by the
47-
// use of the assertion function. Thus, the only way this can
48-
// modify its argument is if T is an auto_ptr-like type. There
49-
// is still a const-correctness hole w.r.t. auto_ptr<U> const,
50-
// but c'est la vie.
51-
return ToPython::convert(*const_cast<T*>(static_cast<T const*>(x)));
52-
}
53-
};
54-
5518
}}} // namespace boost::python::converter
5619

5720
#endif // TO_PYTHON_FUNCTION_TYPE_DWA200236_HPP

include/boost/python/object/class_converters.hpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,18 @@
66
#ifndef CLASS_CONVERTERS_DWA2002119_HPP
77
# define CLASS_CONVERTERS_DWA2002119_HPP
88

9-
# include <boost/mpl/for_each.hpp>
109
# include <boost/python/converter/registry.hpp>
10+
# include <boost/python/converter/shared_ptr_from_python.hpp>
11+
1112
# include <boost/python/object/find_instance.hpp>
1213
# include <boost/python/object/inheritance.hpp>
14+
1315
# include <boost/python/detail/force_instantiate.hpp>
16+
1417
# include <boost/type_traits/add_pointer.hpp>
1518

19+
# include <boost/mpl/for_each.hpp>
20+
1621
namespace boost { namespace python { namespace objects {
1722

1823
//////////////////////////////////////////////////////////////////////
@@ -62,13 +67,14 @@ struct register_base_of
6267
}
6368
};
6469

65-
// Brings into existence all converters associated with a class Bases
70+
// Brings into existence all converters associated with a class. Bases
6671
// is expected to be an mpl sequence of base types.
6772
template <class Derived, class Bases>
6873
inline void register_class_from_python(Derived* = 0, Bases* = 0)
6974
{
7075
// cause the static registration to be instantiated.
7176
python::detail::force_instantiate(instance_finder<Derived>::registration);
77+
python::detail::force_instantiate(converter::shared_ptr_from_python<Derived>::registration);
7278

7379
// register all up/downcasts here
7480
register_dynamic_id<Derived>();

include/boost/python/object/class_wrapper.hpp

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,26 @@
1111

1212
namespace boost { namespace python { namespace objects {
1313

14-
// Used to convert objects of type Src to wrapped C++ classes by
15-
// building a new instance object and installing a Holder constructed
16-
// from a Src const&.
17-
template <class Src, class Holder, class MakeInstance>
18-
struct class_wrapper
19-
: to_python_converter<Src,class_wrapper<Src,Holder,MakeInstance> >
14+
//
15+
// These two classes adapt the static execute function of a class
16+
// MakeInstance execute() function returning a new PyObject*
17+
// reference. The first one is used for class copy constructors, and
18+
// the second one is used to handle smart pointers.
19+
//
20+
21+
template <class Src, class MakeInstance>
22+
struct class_cref_wrapper
23+
: to_python_converter<Src,class_cref_wrapper<Src,MakeInstance> >
2024
{
2125
static PyObject* convert(Src const& x)
2226
{
2327
return MakeInstance::execute(boost::ref(x));
2428
}
2529
};
2630

27-
// Used to convert objects of type Src to wrapped C++ classes by
28-
// building a new instance object and installing a Holder constructed
29-
// from a Src value.
30-
template <class Src, class Holder, class MakeInstance>
31+
template <class Src, class MakeInstance>
3132
struct class_value_wrapper
32-
: to_python_converter<Src,class_value_wrapper<Src,Holder,MakeInstance> >
33+
: to_python_converter<Src,class_value_wrapper<Src,MakeInstance> >
3334
{
3435
static PyObject* convert(Src x)
3536
{

include/boost/python/object/select_holder.hpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,7 @@ namespace detail
130130
static inline void register_(mpl::bool_c<false>)
131131
{
132132
python::detail::force_instantiate(
133-
objects::class_value_wrapper<
134-
Ptr
135-
, type
136-
, make_instance<T,type> >());
133+
objects::class_value_wrapper<Ptr, make_instance<T,type> >());
137134

138135
python::detail::force_instantiate(
139136
instance_finder<Ptr>::registration);

include/boost/python/to_python_converter.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
# define TO_PYTHON_CONVERTER_DWA200221_HPP
88

99
# include <boost/python/converter/registry.hpp>
10-
# include <boost/python/converter/to_python_function_type.hpp>
10+
# include <boost/python/converter/as_to_python_function.hpp>
1111
# include <boost/python/type_id.hpp>
1212

1313
namespace boost { namespace python {

test/Jamfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ run ../test/embedding.cpp <dll>../build/boost_python
6363
<library-path>$(PYTHON_LIB_PATH)
6464
<find-library>$(PYTHON_EMBEDDED_LIBRARY) ;
6565

66+
bpl-test shared_ptr ;
6667
bpl-test polymorphism ;
6768
bpl-test auto_ptr ;
6869
bpl-test minimal ;

test/bienstman1.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ BOOST_PYTHON_MODULE(bienstman1_ext)
2525
using boost::python::return_value_policy;
2626
using boost::python::reference_existing_object;
2727

28-
class_<A, shared_ptr<A> >("A");
28+
class_<A>("A");
2929

3030
class_<V, boost::noncopyable>("V", no_init)
3131
.def("inside", &V::inside,

0 commit comments

Comments
 (0)