Chris@16
|
1 // Copyright David Abrahams 2002.
|
Chris@16
|
2 // Distributed under the Boost Software License, Version 1.0. (See
|
Chris@16
|
3 // accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
4 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
5 #ifndef OBJECT_MANAGER_DWA2002614_HPP
|
Chris@16
|
6 # define OBJECT_MANAGER_DWA2002614_HPP
|
Chris@16
|
7
|
Chris@16
|
8 # include <boost/python/handle.hpp>
|
Chris@16
|
9 # include <boost/python/cast.hpp>
|
Chris@16
|
10 # include <boost/python/converter/pyobject_traits.hpp>
|
Chris@16
|
11 # include <boost/type_traits/object_traits.hpp>
|
Chris@16
|
12 # include <boost/mpl/if.hpp>
|
Chris@16
|
13 # include <boost/python/detail/indirect_traits.hpp>
|
Chris@16
|
14 # include <boost/mpl/bool.hpp>
|
Chris@16
|
15
|
Chris@16
|
16 // Facilities for dealing with types which always manage Python
|
Chris@16
|
17 // objects. Some examples are object, list, str, et. al. Different
|
Chris@16
|
18 // to_python/from_python conversion rules apply here because in
|
Chris@16
|
19 // contrast to other types which are typically embedded inside a
|
Chris@16
|
20 // Python object, these are wrapped around a Python object. For most
|
Chris@16
|
21 // object managers T, a C++ non-const T reference argument does not
|
Chris@16
|
22 // imply the existence of a T lvalue embedded in the corresponding
|
Chris@16
|
23 // Python argument, since mutating member functions on T actually only
|
Chris@16
|
24 // modify the held Python object.
|
Chris@16
|
25 //
|
Chris@16
|
26 // handle<T> is an object manager, though strictly speaking it should
|
Chris@16
|
27 // not be. In other words, even though mutating member functions of
|
Chris@16
|
28 // hanlde<T> actually modify the handle<T> and not the T object,
|
Chris@16
|
29 // handle<T>& arguments of wrapped functions will bind to "rvalues"
|
Chris@16
|
30 // wrapping the actual Python argument, just as with other object
|
Chris@16
|
31 // manager classes. Making an exception for handle<T> is simply not
|
Chris@16
|
32 // worth the trouble.
|
Chris@16
|
33 //
|
Chris@16
|
34 // borrowed<T> cv* is an object manager so that we can use the general
|
Chris@16
|
35 // to_python mechanisms to convert raw Python object pointers to
|
Chris@16
|
36 // python, without the usual semantic problems of using raw pointers.
|
Chris@16
|
37
|
Chris@16
|
38
|
Chris@16
|
39 // Object Manager Concept requirements:
|
Chris@16
|
40 //
|
Chris@16
|
41 // T is an Object Manager
|
Chris@16
|
42 // p is a PyObject*
|
Chris@16
|
43 // x is a T
|
Chris@16
|
44 //
|
Chris@16
|
45 // * object_manager_traits<T>::is_specialized == true
|
Chris@16
|
46 //
|
Chris@16
|
47 // * T(detail::borrowed_reference(p))
|
Chris@16
|
48 // Manages p without checking its type
|
Chris@16
|
49 //
|
Chris@16
|
50 // * get_managed_object(x, boost::python::tag)
|
Chris@16
|
51 // Convertible to PyObject*
|
Chris@16
|
52 //
|
Chris@16
|
53 // Additional requirements if T can be converted from_python:
|
Chris@16
|
54 //
|
Chris@16
|
55 // * T(object_manager_traits<T>::adopt(p))
|
Chris@16
|
56 // steals a reference to p, or throws a TypeError exception if
|
Chris@16
|
57 // p doesn't have an appropriate type. May assume p is non-null
|
Chris@16
|
58 //
|
Chris@16
|
59 // * X::check(p)
|
Chris@16
|
60 // convertible to bool. True iff T(X::construct(p)) will not
|
Chris@16
|
61 // throw.
|
Chris@16
|
62
|
Chris@16
|
63 // Forward declarations
|
Chris@16
|
64 //
|
Chris@16
|
65 namespace boost { namespace python
|
Chris@16
|
66 {
|
Chris@16
|
67 namespace api
|
Chris@16
|
68 {
|
Chris@16
|
69 class object;
|
Chris@16
|
70 }
|
Chris@16
|
71 }}
|
Chris@16
|
72
|
Chris@16
|
73 namespace boost { namespace python { namespace converter {
|
Chris@16
|
74
|
Chris@16
|
75
|
Chris@16
|
76 // Specializations for handle<T>
|
Chris@16
|
77 template <class T>
|
Chris@16
|
78 struct handle_object_manager_traits
|
Chris@16
|
79 : pyobject_traits<typename T::element_type>
|
Chris@16
|
80 {
|
Chris@16
|
81 private:
|
Chris@16
|
82 typedef pyobject_traits<typename T::element_type> base;
|
Chris@16
|
83
|
Chris@16
|
84 public:
|
Chris@16
|
85 BOOST_STATIC_CONSTANT(bool, is_specialized = true);
|
Chris@16
|
86
|
Chris@16
|
87 // Initialize with a null_ok pointer for efficiency, bypassing the
|
Chris@16
|
88 // null check since the source is always non-null.
|
Chris@16
|
89 static null_ok<typename T::element_type>* adopt(PyObject* p)
|
Chris@16
|
90 {
|
Chris@16
|
91 return python::allow_null(base::checked_downcast(p));
|
Chris@16
|
92 }
|
Chris@16
|
93 };
|
Chris@16
|
94
|
Chris@16
|
95 template <class T>
|
Chris@16
|
96 struct default_object_manager_traits
|
Chris@16
|
97 {
|
Chris@16
|
98 BOOST_STATIC_CONSTANT(
|
Chris@16
|
99 bool, is_specialized = python::detail::is_borrowed_ptr<T>::value
|
Chris@16
|
100 );
|
Chris@16
|
101 };
|
Chris@16
|
102
|
Chris@16
|
103 template <class T>
|
Chris@16
|
104 struct object_manager_traits
|
Chris@16
|
105 : mpl::if_c<
|
Chris@16
|
106 is_handle<T>::value
|
Chris@16
|
107 , handle_object_manager_traits<T>
|
Chris@16
|
108 , default_object_manager_traits<T>
|
Chris@16
|
109 >::type
|
Chris@16
|
110 {
|
Chris@16
|
111 };
|
Chris@16
|
112
|
Chris@16
|
113 //
|
Chris@16
|
114 // Traits for detecting whether a type is an object manager or a
|
Chris@16
|
115 // (cv-qualified) reference to an object manager.
|
Chris@16
|
116 //
|
Chris@16
|
117
|
Chris@16
|
118 template <class T>
|
Chris@16
|
119 struct is_object_manager
|
Chris@16
|
120 : mpl::bool_<object_manager_traits<T>::is_specialized>
|
Chris@16
|
121 {
|
Chris@16
|
122 };
|
Chris@16
|
123
|
Chris@16
|
124 # ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
Chris@16
|
125 template <class T>
|
Chris@16
|
126 struct is_reference_to_object_manager
|
Chris@16
|
127 : mpl::false_
|
Chris@16
|
128 {
|
Chris@16
|
129 };
|
Chris@16
|
130
|
Chris@16
|
131 template <class T>
|
Chris@16
|
132 struct is_reference_to_object_manager<T&>
|
Chris@16
|
133 : is_object_manager<T>
|
Chris@16
|
134 {
|
Chris@16
|
135 };
|
Chris@16
|
136
|
Chris@16
|
137 template <class T>
|
Chris@16
|
138 struct is_reference_to_object_manager<T const&>
|
Chris@16
|
139 : is_object_manager<T>
|
Chris@16
|
140 {
|
Chris@16
|
141 };
|
Chris@16
|
142
|
Chris@16
|
143 template <class T>
|
Chris@16
|
144 struct is_reference_to_object_manager<T volatile&>
|
Chris@16
|
145 : is_object_manager<T>
|
Chris@16
|
146 {
|
Chris@16
|
147 };
|
Chris@16
|
148
|
Chris@16
|
149 template <class T>
|
Chris@16
|
150 struct is_reference_to_object_manager<T const volatile&>
|
Chris@16
|
151 : is_object_manager<T>
|
Chris@16
|
152 {
|
Chris@16
|
153 };
|
Chris@16
|
154 # else
|
Chris@16
|
155
|
Chris@16
|
156 namespace detail
|
Chris@16
|
157 {
|
Chris@16
|
158 typedef char (&yes_reference_to_object_manager)[1];
|
Chris@16
|
159 typedef char (&no_reference_to_object_manager)[2];
|
Chris@16
|
160
|
Chris@16
|
161 // A number of nastinesses go on here in order to work around MSVC6
|
Chris@16
|
162 // bugs.
|
Chris@16
|
163 template <class T>
|
Chris@16
|
164 struct is_object_manager_help
|
Chris@16
|
165 {
|
Chris@16
|
166 typedef typename mpl::if_<
|
Chris@16
|
167 is_object_manager<T>
|
Chris@16
|
168 , yes_reference_to_object_manager
|
Chris@16
|
169 , no_reference_to_object_manager
|
Chris@16
|
170 >::type type;
|
Chris@16
|
171
|
Chris@16
|
172 // If we just use the type instead of the result of calling this
|
Chris@16
|
173 // function, VC6 will ICE.
|
Chris@16
|
174 static type call();
|
Chris@16
|
175 };
|
Chris@16
|
176
|
Chris@16
|
177 // A set of overloads for each cv-qualification. The same argument
|
Chris@16
|
178 // is passed twice: the first one is used to unwind the cv*, and the
|
Chris@16
|
179 // second one is used to avoid relying on partial ordering for
|
Chris@16
|
180 // overload resolution.
|
Chris@16
|
181 template <class U>
|
Chris@16
|
182 typename is_object_manager_help<U>
|
Chris@16
|
183 is_object_manager_helper(U*, void*);
|
Chris@16
|
184
|
Chris@16
|
185 template <class U>
|
Chris@16
|
186 typename is_object_manager_help<U>
|
Chris@16
|
187 is_object_manager_helper(U const*, void const*);
|
Chris@16
|
188
|
Chris@16
|
189 template <class U>
|
Chris@16
|
190 typename is_object_manager_help<U>
|
Chris@16
|
191 is_object_manager_helper(U volatile*, void volatile*);
|
Chris@16
|
192
|
Chris@16
|
193 template <class U>
|
Chris@16
|
194 typename is_object_manager_help<U>
|
Chris@16
|
195 is_object_manager_helper(U const volatile*, void const volatile*);
|
Chris@16
|
196
|
Chris@16
|
197 template <class T>
|
Chris@16
|
198 struct is_reference_to_object_manager_nonref
|
Chris@16
|
199 : mpl::false_
|
Chris@16
|
200 {
|
Chris@16
|
201 };
|
Chris@16
|
202
|
Chris@16
|
203 template <class T>
|
Chris@16
|
204 struct is_reference_to_object_manager_ref
|
Chris@16
|
205 {
|
Chris@16
|
206 static T sample_object;
|
Chris@16
|
207 BOOST_STATIC_CONSTANT(
|
Chris@16
|
208 bool, value
|
Chris@16
|
209 = (sizeof(is_object_manager_helper(&sample_object, &sample_object).call())
|
Chris@16
|
210 == sizeof(detail::yes_reference_to_object_manager)
|
Chris@16
|
211 )
|
Chris@16
|
212 );
|
Chris@16
|
213 typedef mpl::bool_<value> type;
|
Chris@16
|
214 };
|
Chris@16
|
215 }
|
Chris@16
|
216
|
Chris@16
|
217 template <class T>
|
Chris@16
|
218 struct is_reference_to_object_manager
|
Chris@16
|
219 : mpl::if_<
|
Chris@16
|
220 is_reference<T>
|
Chris@16
|
221 , detail::is_reference_to_object_manager_ref<T>
|
Chris@16
|
222 , detail::is_reference_to_object_manager_nonref<T>
|
Chris@16
|
223 >::type
|
Chris@16
|
224 {
|
Chris@16
|
225 };
|
Chris@16
|
226 # endif
|
Chris@16
|
227
|
Chris@16
|
228 }}} // namespace boost::python::converter
|
Chris@16
|
229
|
Chris@16
|
230 #endif // OBJECT_MANAGER_DWA2002614_HPP
|