Skip to content

Commit 3d874d1

Browse files
committed
Major simplification of from_python conversion avoids registering
converters for every class. [SVN r16669]
1 parent b8edd99 commit 3d874d1

File tree

12 files changed

+177
-151
lines changed

12 files changed

+177
-151
lines changed

include/boost/python/class.hpp

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -77,21 +77,21 @@ namespace detail
7777
template <detail::operator_id, class L, class R>
7878
struct operator_;
7979

80-
// Register a to_python converter for a class T, depending on the
81-
// type of the first (tag) argument. The 2nd argument is a pointer
82-
// to the type of holder that must be created. The 3rd argument is a
80+
// Register to_python converters for a class T. The first argument
81+
// will be mpl::true_c unless noncopyable was specified as a
82+
// class_<...> template parameter. The 2nd argument is a pointer to
83+
// the type of holder that must be created. The 3rd argument is a
8384
// reference to the Python type object to be created.
8485
template <class T, class SelectHolder>
85-
static inline void register_copy_constructor(mpl::bool_c<true> const&, SelectHolder const& , T* = 0)
86+
inline void register_class_to_python(mpl::true_c copyable, SelectHolder selector, T* = 0)
8687
{
8788
typedef typename SelectHolder::type holder;
8889
force_instantiate(objects::class_cref_wrapper<T, objects::make_instance<T,holder> >());
8990
SelectHolder::register_();
9091
}
9192

92-
// Tag dispatched to have no effect.
9393
template <class T, class SelectHolder>
94-
static inline void register_copy_constructor(mpl::bool_c<false> const&, SelectHolder const&, T* = 0)
94+
inline void register_class_to_python(mpl::false_c copyable, SelectHolder selector, T* = 0)
9595
{
9696
SelectHolder::register_();
9797
}
@@ -125,20 +125,14 @@ namespace detail
125125

126126
template <class T, class Fn>
127127
struct virtual_function_default
128-
# if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
129-
: assertion<is_polymorphic<T> >::failed
130-
, assertion<is_member_function_pointer<Fn> >::failed
131-
# endif
132128
{
133129
template <class Default>
134130
static void
135131
must_be_derived_class_member(Default const&)
136132
{
137133
typedef typename assertion<mpl::logical_not<is_same<Default,Fn> > >::failed test0;
138-
# if defined(BOOST_MSVC) && BOOST_MSVC <= 1300
139134
typedef typename assertion<is_polymorphic<T> >::failed test1;
140135
typedef typename assertion<is_member_function_pointer<Fn> >::failed test2;
141-
# endif
142136
not_a_derived_class_member<Default>(Fn());
143137
}
144138
};
@@ -473,7 +467,7 @@ inline void class_<T,X1,X2,X3>::register_() const
473467
{
474468
objects::register_class_from_python<T,bases>();
475469

476-
detail::register_copy_constructor<T>(
470+
detail::register_class_to_python<T>(
477471
mpl::bool_c<is_copyable>()
478472
, holder_selector::execute((held_type*)0)
479473
);

include/boost/python/converter/from_python.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ struct rvalue_from_python_chain;
1818
BOOST_PYTHON_DECL void* get_lvalue_from_python(
1919
PyObject* source, registration const&);
2020

21-
BOOST_PYTHON_DECL rvalue_from_python_chain const* implicit_conversion_chain(
21+
BOOST_PYTHON_DECL bool implicit_rvalue_convertible_from_python(
2222
PyObject* source, registration const&);
2323

2424
BOOST_PYTHON_DECL rvalue_from_python_stage1_data rvalue_from_python_stage1(

include/boost/python/converter/implicit.hpp

Lines changed: 12 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,50 +5,36 @@
55
// to its suitability for any purpose.
66
#ifndef IMPLICIT_DWA2002326_HPP
77
# define IMPLICIT_DWA2002326_HPP
8+
89
# include <boost/python/converter/rvalue_from_python_data.hpp>
910
# include <boost/python/converter/registrations.hpp>
1011
# include <boost/python/converter/registered.hpp>
1112

13+
# include <boost/python/extract.hpp>
14+
1215
namespace boost { namespace python { namespace converter {
1316

1417
template <class Source, class Target>
1518
struct implicit
1619
{
1720
static void* convertible(PyObject* obj)
1821
{
19-
// Find a converter chain which can produce a Source instance
20-
// from obj. The user has told us that Source can be converted
21-
// to Target, and instantiating construct() below, ensures
22-
// that at compile-time.
23-
return const_cast<rvalue_from_python_chain*>(
24-
converter::implicit_conversion_chain(obj, registered<Source>::converters));
22+
// Find a converter which can produce a Source instance from
23+
// obj. The user has told us that Source can be converted to
24+
// Target, and instantiating construct() below, ensures that
25+
// at compile-time.
26+
return implicit_rvalue_convertible_from_python(obj, registered<Source>::converters)
27+
? obj : 0;
2528
}
2629

2730
static void construct(PyObject* obj, rvalue_from_python_stage1_data* data)
2831
{
29-
// This is the chain we got from the convertible step
30-
rvalue_from_python_chain const* chain
31-
= static_cast<rvalue_from_python_chain*>(data->convertible);
32-
33-
// Call the convertible function again
34-
rvalue_from_python_data<Source> intermediate_data(chain->convertible(obj));
35-
36-
// Use the result to construct the source type if the first
37-
// converter was an rvalue converter.
38-
if (chain->construct != 0)
39-
chain->construct(obj, &intermediate_data.stage1);
40-
4132
void* storage = ((rvalue_from_python_storage<Target>*)data)->storage.bytes;
42-
# if !defined(BOOST_MSVC) || _MSC_FULL_VER != 13012108 // vc7.01 alpha workaround
43-
new (storage) Target(*static_cast<Source*>(intermediate_data.stage1.convertible));
44-
# else
45-
Target x(*static_cast<Source*>(intermediate_data.stage1.convertible));
46-
new (storage) Target(x);
47-
# endif
48-
33+
34+
new (storage) Target(extract<Source>(obj)());
35+
4936
// record successful construction
5037
data->convertible = storage;
51-
5238
}
5339
};
5440

include/boost/python/converter/registrations.hpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,15 @@
66
#ifndef REGISTRATIONS_DWA2002223_HPP
77
# define REGISTRATIONS_DWA2002223_HPP
88

9-
# include <boost/python/detail/wrap_python.hpp>
9+
# include <boost/python/type_id.hpp>
10+
1011
# include <boost/python/converter/convertible_function.hpp>
1112
# include <boost/python/converter/constructor_function.hpp>
1213
# include <boost/python/converter/to_python_function_type.hpp>
13-
# include <boost/python/type_id.hpp>
14+
15+
# include <boost/python/detail/wrap_python.hpp>
16+
17+
# include <boost/detail/workaround.hpp>
1418

1519
namespace boost { namespace python { namespace converter {
1620

@@ -54,7 +58,7 @@ struct BOOST_PYTHON_DECL registration
5458
// The unique to_python converter for the associated C++ type.
5559
to_python_function_t m_to_python;
5660

57-
# if defined(__MWERKS__) && __MWERKS__ <= 0x3003
61+
# if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3003))
5862
private:
5963
void operator=(registration); // This is not defined, and just keeps MWCW happy.
6064
# endif

include/boost/python/object/class_converters.hpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
# include <boost/python/converter/registry.hpp>
1010
# include <boost/python/converter/shared_ptr_from_python.hpp>
1111

12-
# include <boost/python/object/find_instance.hpp>
1312
# include <boost/python/object/inheritance.hpp>
1413

1514
# include <boost/python/detail/force_instantiate.hpp>
@@ -72,8 +71,6 @@ struct register_base_of
7271
template <class Derived, class Bases>
7372
inline void register_class_from_python(Derived* = 0, Bases* = 0)
7473
{
75-
// cause the static registration to be instantiated.
76-
python::detail::force_instantiate(instance_finder<Derived>::registration);
7774
python::detail::force_instantiate(converter::shared_ptr_from_python<Derived>::registration);
7875

7976
// register all up/downcasts here

include/boost/python/object/find_instance.hpp

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,34 +7,13 @@
77
# define FIND_INSTANCE_DWA2002312_HPP
88

99
# include <boost/python/type_id.hpp>
10-
# include <boost/python/converter/registry.hpp>
1110

1211
namespace boost { namespace python { namespace objects {
1312

1413
// Given a type_id, find the instance data which corresponds to it, or
1514
// return 0 in case no such type is held.
1615
BOOST_PYTHON_DECL void* find_instance_impl(PyObject*, type_info);
1716

18-
// This produces a function with the right signature for use in from_python conversions
19-
template <class T>
20-
struct instance_finder
21-
{
22-
instance_finder()
23-
{
24-
converter::registry::insert(&execute, python::type_id<T>());
25-
}
26-
27-
static instance_finder const registration;
28-
private:
29-
static inline void* execute(PyObject* p)
30-
{
31-
return find_instance_impl(p, python::type_id<T>());
32-
}
33-
};
34-
35-
template <class T>
36-
instance_finder<T> const instance_finder<T>::registration;
37-
3817
}}} // namespace boost::python::objects
3918

4019
#endif // FIND_INSTANCE_DWA2002312_HPP

include/boost/python/object/make_instance.hpp

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,15 @@
1111

1212
namespace boost { namespace python { namespace objects {
1313

14+
struct decref_guard
15+
{
16+
decref_guard(PyObject* o) : obj(o) {}
17+
~decref_guard() { Py_XDECREF(obj); }
18+
void cancel() { obj = 0; }
19+
private:
20+
PyObject* obj;
21+
};
22+
1423
template <class T, class Holder>
1524
struct make_instance
1625
{
@@ -28,22 +37,20 @@ struct make_instance
2837

2938
if (raw_result != 0)
3039
{
31-
instance_t* result = (instance_t*)raw_result;
32-
try
33-
{
34-
// construct the new C++ object and install the pointer
35-
// in the Python object.
36-
construct(result, x)->install(raw_result);
37-
}
38-
catch(...)
39-
{
40-
Py_DECREF(raw_result); // reclaim the Python object
41-
throw;
42-
}
40+
decref_guard protect(raw_result);
41+
42+
instance_t* instance = (instance_t*)raw_result;
43+
44+
// construct the new C++ object and install the pointer
45+
// in the Python object.
46+
construct(instance, x)->install(raw_result);
4347

4448
// Note the position of the internally-stored Holder,
4549
// for the sake of destruction
46-
result->ob_size = offsetof(instance_t, storage);
50+
instance->ob_size = offsetof(instance_t, storage);
51+
52+
// Release ownership of the python object
53+
protect.cancel();
4754
}
4855
return raw_result;
4956
}

include/boost/python/object/pointer_holder.hpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
# include <boost/python/instance_holder.hpp>
1515
# include <boost/python/type_id.hpp>
1616
# include <boost/python/object/inheritance.hpp>
17-
# include <boost/python/object/find_instance.hpp>
1817
# include <boost/python/object/forward.hpp>
1918
# include <boost/python/pointee.hpp>
2019
# include <boost/python/detail/force_instantiate.hpp>

0 commit comments

Comments
 (0)