]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Copyright David Abrahams 2002. |
2 | // Distributed under the Boost Software License, Version 1.0. (See | |
3 | // accompanying file LICENSE_1_0.txt or copy at | |
4 | // http://www.boost.org/LICENSE_1_0.txt) | |
5 | #ifndef OBJECT_MANAGER_DWA2002614_HPP | |
6 | # define OBJECT_MANAGER_DWA2002614_HPP | |
7 | ||
8 | # include <boost/python/handle.hpp> | |
9 | # include <boost/python/cast.hpp> | |
10 | # include <boost/python/converter/pyobject_traits.hpp> | |
11 | # include <boost/type_traits/object_traits.hpp> | |
12 | # include <boost/mpl/if.hpp> | |
13 | # include <boost/python/detail/indirect_traits.hpp> | |
14 | # include <boost/mpl/bool.hpp> | |
15 | ||
16 | // Facilities for dealing with types which always manage Python | |
17 | // objects. Some examples are object, list, str, et. al. Different | |
18 | // to_python/from_python conversion rules apply here because in | |
19 | // contrast to other types which are typically embedded inside a | |
20 | // Python object, these are wrapped around a Python object. For most | |
21 | // object managers T, a C++ non-const T reference argument does not | |
22 | // imply the existence of a T lvalue embedded in the corresponding | |
23 | // Python argument, since mutating member functions on T actually only | |
24 | // modify the held Python object. | |
25 | // | |
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. | |
37 | ||
38 | ||
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* | |
52 | // | |
53 | // Additional requirements if T can be converted from_python: | |
54 | // | |
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 | |
58 | // | |
59 | // * X::check(p) | |
60 | // convertible to bool. True iff T(X::construct(p)) will not | |
61 | // throw. | |
62 | ||
63 | // Forward declarations | |
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 | ||
103 | template <class T> | |
104 | struct object_manager_traits | |
105 | : mpl::if_c< | |
106 | is_handle<T>::value | |
107 | , handle_object_manager_traits<T> | |
108 | , default_object_manager_traits<T> | |
109 | >::type | |
110 | { | |
111 | }; | |
112 | ||
113 | // | |
114 | // Traits for detecting whether a type is an object manager or a | |
115 | // (cv-qualified) reference to an object manager. | |
116 | // | |
117 | ||
118 | template <class T> | |
119 | struct is_object_manager | |
120 | : mpl::bool_<object_manager_traits<T>::is_specialized> | |
121 | { | |
122 | }; | |
123 | ||
124 | template <class T> | |
125 | struct is_reference_to_object_manager | |
126 | : mpl::false_ | |
127 | { | |
128 | }; | |
129 | ||
130 | template <class T> | |
131 | struct is_reference_to_object_manager<T&> | |
132 | : is_object_manager<T> | |
133 | { | |
134 | }; | |
135 | ||
136 | template <class T> | |
137 | struct is_reference_to_object_manager<T const&> | |
138 | : is_object_manager<T> | |
139 | { | |
140 | }; | |
141 | ||
142 | template <class T> | |
143 | struct is_reference_to_object_manager<T volatile&> | |
144 | : is_object_manager<T> | |
145 | { | |
146 | }; | |
147 | ||
148 | template <class T> | |
149 | struct is_reference_to_object_manager<T const volatile&> | |
150 | : is_object_manager<T> | |
151 | { | |
152 | }; | |
153 | ||
154 | }}} // namespace boost::python::converter | |
155 | ||
156 | #endif // OBJECT_MANAGER_DWA2002614_HPP |