Skip to content

Commit 390bb19

Browse files
committed
implemented back_reference<>
[SVN r13811]
1 parent 63deae3 commit 390bb19

File tree

4 files changed

+158
-1
lines changed

4 files changed

+158
-1
lines changed
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
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 BACK_REFERENCE_DWA2002510_HPP
7+
# define BACK_REFERENCE_DWA2002510_HPP
8+
9+
# include <boost/python/reference.hpp>
10+
11+
namespace boost { namespace python {
12+
13+
template <class T>
14+
struct back_reference
15+
{
16+
public:
17+
typedef T type;
18+
19+
back_reference(PyObject*, T);
20+
ref reference() const;
21+
T get() const;
22+
private:
23+
ref m_reference;
24+
T m_value;
25+
};
26+
27+
# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
28+
template<typename T>
29+
class is_back_reference
30+
{
31+
public:
32+
BOOST_STATIC_CONSTANT(bool, value = false);
33+
};
34+
35+
template<typename T>
36+
class is_back_reference<back_reference<T> >
37+
{
38+
public:
39+
BOOST_STATIC_CONSTANT(bool, value = true);
40+
};
41+
42+
# else // no partial specialization
43+
44+
}} // namespace boost::python
45+
46+
#include <boost/type.hpp>
47+
48+
namespace boost { namespace python {
49+
50+
namespace detail
51+
{
52+
typedef char (&yes_back_reference_t)[1];
53+
typedef char (&no_back_reference_t)[2];
54+
55+
no_back_reference_t is_back_reference_test(...);
56+
57+
template<typename T>
58+
yes_back_reference_t is_back_reference_test(type< back_reference<T> >);
59+
}
60+
61+
template<typename T>
62+
class is_back_reference
63+
{
64+
public:
65+
BOOST_STATIC_CONSTANT(
66+
bool, value = (
67+
sizeof(detail::is_back_reference_test(type<T>()))
68+
== sizeof(detail::yes_back_reference_t)));
69+
};
70+
71+
# endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
72+
73+
//
74+
// implementations
75+
//
76+
template <class T>
77+
back_reference<T>::back_reference(PyObject* p, T x)
78+
: m_reference(p, ref::increment_count)
79+
, m_value(x)
80+
{
81+
}
82+
83+
template <class T>
84+
ref back_reference<T>::reference() const
85+
{
86+
return m_reference;
87+
}
88+
89+
template <class T>
90+
T back_reference<T>::get() const
91+
{
92+
return m_value;
93+
}
94+
95+
}} // namespace boost::python
96+
97+
#endif // BACK_REFERENCE_DWA2002510_HPP

include/boost/python/converter/from_python.hpp

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@
1616
# include <boost/python/converter/lvalue_from_python_chain.hpp>
1717
# include <boost/python/converter/rvalue_from_python_chain.hpp>
1818
# include <boost/python/detail/void_ptr.hpp>
19+
# include <boost/python/back_reference.hpp>
20+
21+
namespace boost { namespace python
22+
{
23+
template <class T> struct from_python;
24+
}}
1925

2026
namespace boost { namespace python { namespace converter {
2127

@@ -82,6 +88,21 @@ class rvalue_from_python
8288
rvalue_data<result_type> m_data;
8389
};
8490

91+
// ------- back-reference converters --------
92+
93+
// Converts to a (PyObject*,T) bundle, for when you need a reference
94+
// back to the Python object
95+
96+
template <class T>
97+
struct back_reference_from_python
98+
: boost::python::from_python<typename T::type>
99+
{
100+
back_reference_from_python(PyObject*);
101+
T operator()(PyObject*);
102+
private:
103+
typedef boost::python::from_python<typename T::type> base;
104+
};
105+
85106
template <class T>
86107
struct select_from_python
87108
{
@@ -100,6 +121,10 @@ struct select_from_python
100121
boost::python::detail::is_reference_to_non_const<T>::value
101122
|| boost::python::detail::is_reference_to_volatile<T>::value);
102123

124+
BOOST_STATIC_CONSTANT(
125+
bool, back_ref =
126+
boost::python::is_back_reference<T>::value);
127+
103128
typedef typename mpl::select_type<
104129
ptr
105130
, pointer_from_python<T>
@@ -109,7 +134,11 @@ struct select_from_python
109134
, typename mpl::select_type<
110135
ref
111136
, reference_from_python<T>
112-
, rvalue_from_python<T>
137+
, typename mpl::select_type<
138+
back_ref
139+
, back_reference_from_python<T>
140+
, rvalue_from_python<T>
141+
>::type
113142
>::type
114143
>::type
115144
>::type type;
@@ -232,6 +261,19 @@ rvalue_from_python<T>::operator()(PyObject* p)
232261
return python::detail::void_ptr_to_reference(m_data.stage1.convertible, (result_type(*)())0);
233262
}
234263

264+
template <class T>
265+
back_reference_from_python<T>::back_reference_from_python(PyObject* x)
266+
: base(x)
267+
{
268+
}
269+
270+
template <class T>
271+
inline T
272+
back_reference_from_python<T>::operator()(PyObject* x)
273+
{
274+
return T(x, base::operator()(x));
275+
}
276+
235277
}}} // namespace boost::python::converter
236278

237279
#endif // FROM_PYTHON_DWA2002127_HPP

test/back_reference.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <boost/python/class.hpp>
77
#include <boost/python/module.hpp>
88
#include <boost/python/has_back_reference.hpp>
9+
#include <boost/python/back_reference.hpp>
910
#include <boost/ref.hpp>
1011
#include <boost/utility.hpp>
1112
#include <memory>
@@ -73,6 +74,17 @@ namespace boost { namespace python
7374
};
7475
}}
7576

77+
// prove that back_references get initialized with the right PyObject*
78+
PyObject* y_identity(back_reference<Y const&> y)
79+
{
80+
return y.reference().release();
81+
}
82+
83+
// prove that back_references contain the right value
84+
bool y_equality(back_reference<Y const&> y1, Y const& y2)
85+
{
86+
return &y1.get() == &y2;
87+
}
7688

7789
BOOST_PYTHON_MODULE_INIT(back_reference_ext)
7890
{
@@ -93,6 +105,8 @@ BOOST_PYTHON_MODULE_INIT(back_reference_ext)
93105
.def("value", &Z::value)
94106
.def("set", &Z::set)
95107
)
108+
.def("y_identity", y_identity)
109+
.def("y_equality", y_equality)
96110
;
97111
}
98112

test/back_reference.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
>>> z2 = copy_Z(z)
1111
>>> x_instances()
1212
4
13+
>>> y_identity(y) is y
14+
1
15+
>>> y_equality(y, y)
16+
1
1317
'''
1418

1519
def run(args = None):

0 commit comments

Comments
 (0)