source: NonGTP/Boost/boost/python/converter/object_manager.hpp @ 857

Revision 857, 6.4 KB checked in by igarcia, 18 years ago (diff)
Line 
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//
65namespace boost { namespace python
66{
67  namespace api
68  {
69    class object;
70  }
71}}
72
73namespace boost { namespace python { namespace converter {
74
75
76// Specializations for handle<T>
77template <class T>
78struct 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
95template <class T>
96struct default_object_manager_traits
97{
98    BOOST_STATIC_CONSTANT(
99        bool, is_specialized = python::detail::is_borrowed_ptr<T>::value
100        );
101};
102
103template <class T>
104struct 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
118template <class T>
119struct is_object_manager
120    : mpl::bool_<object_manager_traits<T>::is_specialized>
121{
122};
123
124# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
125template <class T>
126struct is_reference_to_object_manager
127    : mpl::false_
128{
129};
130
131template <class T>
132struct is_reference_to_object_manager<T&>
133    : is_object_manager<T>
134{
135};
136
137template <class T>
138struct is_reference_to_object_manager<T const&>
139    : is_object_manager<T>
140{
141};
142
143template <class T>
144struct is_reference_to_object_manager<T volatile&>
145    : is_object_manager<T>
146{
147};
148
149template <class T>
150struct is_reference_to_object_manager<T const volatile&>
151    : is_object_manager<T>
152{
153};
154# else
155
156namespace detail
157{
158  typedef char (&yes_reference_to_object_manager)[1];
159  typedef char (&no_reference_to_object_manager)[2];
160
161  // A number of nastinesses go on here in order to work around MSVC6
162  // bugs.
163  template <class T>
164  struct is_object_manager_help
165  {
166      typedef typename mpl::if_<
167          is_object_manager<T>
168          , yes_reference_to_object_manager
169          , no_reference_to_object_manager
170          >::type type;
171
172      // If we just use the type instead of the result of calling this
173      // function, VC6 will ICE.
174      static type call();
175  };
176
177  // A set of overloads for each cv-qualification. The same argument
178  // is passed twice: the first one is used to unwind the cv*, and the
179  // second one is used to avoid relying on partial ordering for
180  // overload resolution.
181  template <class U>
182  typename is_object_manager_help<U>
183  is_object_manager_helper(U*, void*);
184 
185  template <class U>
186  typename is_object_manager_help<U>
187  is_object_manager_helper(U const*, void const*);
188 
189  template <class U>
190  typename is_object_manager_help<U>
191  is_object_manager_helper(U volatile*, void volatile*);
192 
193  template <class U>
194  typename is_object_manager_help<U>
195  is_object_manager_helper(U const volatile*, void const volatile*);
196 
197  template <class T>
198  struct is_reference_to_object_manager_nonref
199      : mpl::false_
200  {
201  };
202
203  template <class T>
204  struct is_reference_to_object_manager_ref
205  {
206      static T sample_object;
207      BOOST_STATIC_CONSTANT(
208        bool, value
209        = (sizeof(is_object_manager_helper(&sample_object, &sample_object).call())
210            == sizeof(detail::yes_reference_to_object_manager)
211          )
212        );
213      typedef mpl::bool_<value> type;
214  };
215}
216
217template <class T>
218struct is_reference_to_object_manager
219    : mpl::if_<
220        is_reference<T>
221        , detail::is_reference_to_object_manager_ref<T>
222        , detail::is_reference_to_object_manager_nonref<T>
223    >::type
224{
225};
226# endif
227
228}}} // namespace boost::python::converter
229
230#endif // OBJECT_MANAGER_DWA2002614_HPP
Note: See TracBrowser for help on using the repository browser.