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