Skip to content

Commit 576269d

Browse files
committed
more implicit conversion work
[SVN r13282]
1 parent ac34e0e commit 576269d

File tree

8 files changed

+73
-6
lines changed

8 files changed

+73
-6
lines changed

include/boost/python/converter/implicit.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ struct implicit
3737
registration->construct(obj, &intermediate_data.stage1);
3838

3939
void* storage = ((rvalue_base_data<Target>*)data)->storage.bytes;
40-
new (storage) Target(*(Source*)intermediate_data.storage.bytes);
40+
new (storage) Target(*static_cast<Source*>(intermediate_data.stage1.convertible));
4141

4242
// record successful construction
4343
data->convertible = storage;

include/boost/python/converter/registry.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,14 @@ namespace registry
3737
, undecorated_type_id_t
3838
);
3939

40+
// Insert an rvalue from_python converter at the tail of the
41+
// chain. Used for implicit conversions
42+
BOOST_PYTHON_DECL void push_back(
43+
void* (*convertible)(PyObject*)
44+
, constructor_function
45+
, undecorated_type_id_t
46+
);
47+
4048
BOOST_PYTHON_DECL PyTypeObject*& class_object(undecorated_type_id_t key);
4149
}
4250

include/boost/python/implicit.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ void implicitly_convertible(boost::type<Source>* = 0, boost::type<Target>* = 0)
1717
{
1818
typedef converter::implicit<Source,Target> functions;
1919

20-
converter::registry::insert(
20+
converter::registry::push_back(
2121
&functions::convertible
2222
, &functions::construct
2323
, converter::undecorated_type_id<Target>());

src/converter/from_python.cpp

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#include <boost/python/converter/find_from_python.hpp>
88
#include <boost/python/converter/registrations.hpp>
99
#include <boost/python/converter/from_python_data.hpp>
10+
#include <vector>
11+
#include <algorithm>
1012

1113
namespace boost { namespace python { namespace converter {
1214

@@ -29,15 +31,38 @@ BOOST_PYTHON_DECL rvalue_stage1_data find(
2931
return data;
3032
}
3133

34+
namespace
35+
{
36+
// Prevent looping in implicit conversions. This could/should be
37+
// much more efficient, but will work for now.
38+
typedef std::vector<rvalue_from_python_registration const*> visited_t;
39+
static visited_t visited;
40+
}
41+
3242
BOOST_PYTHON_DECL rvalue_from_python_registration const* find_chain(
3343
PyObject* source
3444
, rvalue_from_python_registration const* chain)
35-
{
36-
for (;chain != 0; chain = chain->next)
45+
{
46+
visited_t::iterator p = std::lower_bound(visited.begin(), visited.end(), chain);
47+
if (p != visited.end() && *p == chain)
48+
return 0;
49+
50+
visited.insert(p, chain);
51+
try
3752
{
38-
if (chain->convertible(source))
39-
break;
53+
for (;chain != 0; chain = chain->next)
54+
{
55+
if (chain->convertible(source))
56+
break;
57+
}
58+
}
59+
catch(...)
60+
{
61+
visited.erase(p);
62+
throw;
4063
}
64+
p = std::lower_bound(visited.begin(), visited.end(), chain);
65+
visited.erase(p);
4166
return chain;
4267
}
4368

src/converter/registry.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,22 @@ namespace registry
109109
found->m_rvalue_from_python = registration;
110110
}
111111

112+
// Insert an rvalue from_python converter
113+
void push_back(void* (*convertible)(PyObject*)
114+
, constructor_function construct
115+
, undecorated_type_id_t key)
116+
{
117+
rvalue_from_python_registration** found = &find(key)->m_rvalue_from_python;
118+
while (*found != 0)
119+
found = &(*found)->next;
120+
121+
rvalue_from_python_registration *registration = new rvalue_from_python_registration;
122+
registration->convertible = convertible;
123+
registration->construct = construct;
124+
registration->next = 0;
125+
*found = registration;
126+
}
127+
112128
PyTypeObject*& class_object(undecorated_type_id_t key)
113129
{
114130
return find(key)->m_class_object;

test/implicit.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,35 @@
1414
using namespace boost::python;
1515

1616
typedef test_class<> X;
17+
typedef test_class<1> Y;
1718

1819
int x_value(X const& x)
1920
{
2021
return x.value();
2122
}
2223

24+
X make_x(int n) { return X(n); }
25+
2326
BOOST_PYTHON_MODULE_INIT(implicit_ext)
2427
{
2528
implicitly_convertible<int,X>();
2629
module("implicit_ext")
2730
.def("x_value", x_value)
31+
.def("make_x", make_x)
2832
.add(
2933
class_<X>("X")
3034
.def_init(args<int>())
3135
.def("value", &X::value)
3236
.def("set", &X::set)
3337
)
38+
.add(
39+
class_<Y>("Y")
40+
.def_init(args<int>())
41+
.def("value", &Y::value)
42+
.def("set", &Y::set)
43+
)
3444
;
45+
implicitly_convertible<X,int>();
3546
}
3647

3748
#include "module_tail.cpp"

test/implicit.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44
42
55
>>> x_value(42)
66
42
7+
>>> x = make_x(X(42))
8+
>>> x.value()
9+
42
10+
>>> try: make_x('fool')
11+
... except TypeError: pass
12+
... else: print 'no error'
713
'''
814

915
def run(args = None):

test/test_class.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ struct test_class
1616

1717
void set(int x) { assert(magic == 7654321 + n); this->x = x; }
1818
int value() const { assert(magic == 7654321 + n); return x; }
19+
operator int() const { return x; }
1920
static int count() { return counter; }
2021
private:
2122
void operator=(test_class const&);

0 commit comments

Comments
 (0)