source: NonGTP/Boost/boost/python/object_core.hpp @ 857

Revision 857, 13.6 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_CORE_DWA2002615_HPP
6# define OBJECT_CORE_DWA2002615_HPP
7
8# include <boost/python/detail/prefix.hpp>
9
10# include <boost/type.hpp>
11
12# include <boost/python/call.hpp>
13# include <boost/python/handle_fwd.hpp>
14# include <boost/python/errors.hpp>
15# include <boost/python/refcount.hpp>
16# include <boost/python/detail/preprocessor.hpp>
17# include <boost/python/tag.hpp>
18# include <boost/python/def_visitor.hpp>
19
20# include <boost/python/detail/raw_pyobject.hpp>
21# include <boost/python/detail/dependent.hpp>
22
23# include <boost/python/object/forward.hpp>
24# include <boost/python/object/add_to_namespace.hpp>
25
26# include <boost/preprocessor/iterate.hpp>
27# include <boost/preprocessor/debug/line.hpp>
28
29# include <boost/python/detail/is_xxx.hpp>
30# include <boost/python/detail/string_literal.hpp>
31# include <boost/python/detail/def_helper_fwd.hpp>
32
33# include <boost/type_traits/is_same.hpp>
34# include <boost/type_traits/is_convertible.hpp>
35# include <boost/type_traits/remove_reference.hpp>
36
37# if BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
38#  include <boost/type_traits/add_pointer.hpp>
39# endif
40
41# include <boost/mpl/if.hpp>
42
43namespace boost { namespace python {
44
45namespace converter
46{
47  template <class T> struct arg_to_python;
48}
49
50// Put this in an inner namespace so that the generalized operators won't take over
51namespace api
52{
53 
54// This file contains the definition of the object class and enough to
55// construct/copy it, but not enough to do operations like
56// attribute/item access or addition.
57
58  template <class Policies> class proxy;
59 
60  struct const_attribute_policies;
61  struct attribute_policies;
62  struct const_item_policies;
63  struct item_policies;
64  struct const_slice_policies;
65  struct slice_policies;
66  class slice_nil;
67
68  typedef proxy<const_attribute_policies> const_object_attribute;
69  typedef proxy<attribute_policies> object_attribute;
70  typedef proxy<const_item_policies> const_object_item;
71  typedef proxy<item_policies> object_item;
72  typedef proxy<const_slice_policies> const_object_slice;
73  typedef proxy<slice_policies> object_slice;
74
75  //
76  // is_proxy -- proxy type detection
77  //
78  BOOST_PYTHON_IS_XXX_DEF(proxy, boost::python::api::proxy, 1)
79
80  template <class T> struct object_initializer;
81 
82  class object;
83  typedef PyObject* (object::*bool_type)() const;
84 
85  template <class U>
86  class object_operators : public def_visitor<U>
87  {
88   protected:
89# if !defined(BOOST_MSVC) || BOOST_MSVC > 1200
90      typedef object const& object_cref;
91# else
92      typedef object object_cref;
93# endif
94   public:
95      // function call
96      //
97      object operator()() const;
98
99# define BOOST_PP_ITERATION_PARAMS_1 (3, (1, BOOST_PYTHON_MAX_ARITY, <boost/python/object_call.hpp>))
100# include BOOST_PP_ITERATE()
101
102      // truth value testing
103      //
104      operator bool_type() const;
105      bool operator!() const; // needed for vc6
106
107      // Attribute access
108      //
109      const_object_attribute attr(char const*) const;
110      object_attribute attr(char const*);
111
112      // item access
113      //
114      const_object_item operator[](object_cref) const;
115      object_item operator[](object_cref);
116   
117      template <class T>
118      const_object_item
119      operator[](T const& key) const
120# if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
121          ;
122# else
123      {
124          return (*this)[object(key)];
125      }
126# endif
127   
128      template <class T>
129      object_item
130      operator[](T const& key)
131# if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
132          ;
133# else
134      {
135          return (*this)[object(key)];
136      }
137# endif
138
139      // slicing
140      //
141      const_object_slice slice(object_cref, object_cref) const;
142      object_slice slice(object_cref, object_cref);
143
144      const_object_slice slice(slice_nil, object_cref) const;
145      object_slice slice(slice_nil, object_cref);
146                             
147      const_object_slice slice(object_cref, slice_nil) const;
148      object_slice slice(object_cref, slice_nil);
149
150      const_object_slice slice(slice_nil, slice_nil) const;
151      object_slice slice(slice_nil, slice_nil);
152
153      template <class T, class V>
154      const_object_slice
155      slice(T const& start, V const& end) const
156# if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
157          ;
158# else
159      {
160          return this->slice(
161               slice_bound<T>::type(start)
162              ,  slice_bound<V>::type(end));
163      }
164# endif
165   
166      template <class T, class V>
167      object_slice
168      slice(T const& start, V const& end)
169# if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
170          ;
171# else
172      {
173          return this->slice(
174              slice_bound<T>::type(start)
175              , slice_bound<V>::type(end));
176      }
177# endif
178     
179   private: // def visitation for adding callable objects as class methods
180     
181      template <class ClassT, class DocStringT>
182      void visit(ClassT& cl, char const* name, python::detail::def_helper<DocStringT> const& helper) const
183      {
184          // It's too late to specify anything other than docstrings if
185          // the callable object is already wrapped.
186          BOOST_STATIC_ASSERT(
187              (is_same<char const*,DocStringT>::value
188               || detail::is_string_literal<DocStringT const>::value));
189       
190          objects::add_to_namespace(cl, name, this->derived_visitor(), helper.doc());
191      }
192
193      friend class python::def_visitor_access;
194     
195   private:
196     // there is a confirmed CWPro8 codegen bug here. We prevent the
197     // early destruction of a temporary by binding a named object
198     // instead.
199# if __MWERKS__ < 0x3000 || __MWERKS__ > 0x3003
200    typedef object const& object_cref2;
201# else
202    typedef object const object_cref2;
203# endif
204  };
205
206 
207  // VC6 and VC7 require this base class in order to generate the
208  // correct copy constructor for object. We can't define it there
209  // explicitly or it will complain of ambiguity.
210  struct object_base : object_operators<object>
211  {
212      // copy constructor without NULL checking, for efficiency.
213      inline object_base(object_base const&);
214      inline object_base(PyObject* ptr);
215     
216      object_base& operator=(object_base const& rhs);
217      ~object_base();
218       
219      // Underlying object access -- returns a borrowed reference
220      PyObject* ptr() const;
221     
222   private:
223      PyObject* m_ptr;
224  };
225
226# ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
227  template <class T, class U>
228  struct is_derived_impl
229  {
230      static T x;
231      template <class X>
232      static X* to_pointer(X const&);
233     
234      static char test(U const*);
235      typedef char (&no)[2];
236      static no test(...);
237
238      BOOST_STATIC_CONSTANT(bool, value = sizeof(test(to_pointer(x))) == 1);
239  };
240 
241  template <class T, class U>
242  struct is_derived
243    : mpl::bool_<is_derived_impl<T,U>::value>
244  {};
245# else
246  template <class T, class U>
247  struct is_derived
248    : is_convertible<
249          typename remove_reference<T>::type*
250        , U const*
251      >
252  {};
253# endif
254
255  template <class T>
256  typename objects::unforward_cref<T>::type do_unforward_cref(T const& x)
257  {
258# if BOOST_WORKAROUND(__GNUC__, == 2)
259      typedef typename objects::unforward_cref<T>::type ret;
260      return ret(x);
261# else
262      return x;
263# endif
264  }
265
266# if BOOST_WORKAROUND(__GNUC__, == 2)
267  // GCC 2.x has non-const string literals; this hacks around that problem.
268  template <unsigned N>
269  char const (& do_unforward_cref(char const(&x)[N]) )[N]
270  {
271      return x;
272  }
273# endif
274 
275  class object;
276 
277  template <class T>
278  PyObject* object_base_initializer(T const& x)
279  {
280      typedef typename is_derived<
281          BOOST_DEDUCED_TYPENAME objects::unforward_cref<T>::type
282        , object
283      >::type is_obj;
284
285      return object_initializer<
286          BOOST_DEDUCED_TYPENAME unwrap_reference<T>::type
287      >::get(
288            x
289          , is_obj()
290      );
291  }
292 
293  class object : public object_base
294  {
295   public:
296      // default constructor creates a None object
297      object();
298     
299      // explicit conversion from any C++ object to Python
300      template <class T>
301      explicit object(
302          T const& x
303# if BOOST_WORKAROUND(BOOST_MSVC, == 1200)
304          // use some SFINAE to un-confuse MSVC about its
305          // copy-initialization ambiguity claim.
306        , typename mpl::if_<is_proxy<T>,int&,int>::type* = 0
307# endif
308      )
309        : object_base(object_base_initializer(x))
310      {
311      }
312
313      // Throw error_already_set() if the handle is null.
314      BOOST_PYTHON_DECL explicit object(handle<> const&);
315   private:
316     
317   public: // implementation detail -- for internal use only
318      explicit object(detail::borrowed_reference);
319      explicit object(detail::new_reference);
320      explicit object(detail::new_non_null_reference);
321  };
322
323  // Macros for forwarding constructors in classes derived from
324  // object. Derived classes will usually want these as an
325  // implementation detail
326# define BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS_(derived, base)       \
327    inline explicit derived(python::detail::borrowed_reference p)       \
328        : base(p) {}                                                    \
329    inline explicit derived(python::detail::new_reference p)            \
330        : base(p) {}                                                    \
331    inline explicit derived(python::detail::new_non_null_reference p)   \
332        : base(p) {}
333
334# if !defined(BOOST_MSVC) || BOOST_MSVC > 1200
335#  define BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS_
336# else
337  // MSVC6 has a bug which causes an explicit template constructor to
338  // be preferred over an appropriate implicit conversion operator
339  // declared on the argument type. Normally, that would cause a
340  // runtime failure when using extract<T> to extract a type with a
341  // templated constructor. This additional constructor will turn that
342  // runtime failure into an ambiguity error at compile-time due to
343  // the lack of partial ordering, or at least a link-time error if no
344  // generalized template constructor is declared.
345#  define BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(derived, base)       \
346    BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS_(derived, base)            \
347    template <class T>                                                  \
348    explicit derived(extract<T> const&);
349# endif
350
351  //
352  // object_initializer -- get the handle to construct the object with,
353  // based on whether T is a proxy or derived from object
354  //
355  template <bool is_proxy = false, bool is_object_manager = false>
356  struct object_initializer_impl
357  {
358      static PyObject*
359      get(object const& x, mpl::true_)
360      {
361          return python::incref(x.ptr());
362      }
363     
364      template <class T>
365      static PyObject*
366      get(T const& x, mpl::false_)
367      {
368          return python::incref(converter::arg_to_python<T>(x).get());
369      }
370  };
371     
372  template <>
373  struct object_initializer_impl<true, false>
374  {
375      template <class Policies>
376      static PyObject*
377      get(proxy<Policies> const& x, mpl::false_)
378      {
379          return python::incref(x.operator object().ptr());
380      }
381  };
382
383  template <>
384  struct object_initializer_impl<false, true>
385  {
386      template <class T, class U>
387      static PyObject*
388      get(T const& x, U)
389      {
390          return python::incref(get_managed_object(x, tag));
391      }
392  };
393
394  template <>
395  struct object_initializer_impl<true, true>
396  {}; // empty implementation should cause an error
397
398  template <class T>
399  struct object_initializer : object_initializer_impl<
400      is_proxy<T>::value
401    , converter::is_object_manager<T>::value
402  >
403  {};
404
405}
406using api::object;
407template <class T> struct extract;
408
409//
410// implementation
411//
412
413inline object::object()
414    : object_base(python::incref(Py_None))
415{}
416
417// copy constructor without NULL checking, for efficiency
418inline api::object_base::object_base(object_base const& rhs)
419    : m_ptr(python::incref(rhs.m_ptr))
420{}
421
422inline api::object_base::object_base(PyObject* p)
423    : m_ptr(p)
424{}
425
426inline api::object_base& api::object_base::operator=(api::object_base const& rhs)
427{
428    Py_INCREF(rhs.m_ptr);
429    Py_DECREF(this->m_ptr);
430    this->m_ptr = rhs.m_ptr;
431    return *this;
432}
433
434inline api::object_base::~object_base()
435{
436    Py_DECREF(m_ptr);
437}
438
439inline object::object(detail::borrowed_reference p)
440    : object_base(python::incref((PyObject*)p))
441{}
442
443inline object::object(detail::new_reference p)
444    : object_base(expect_non_null((PyObject*)p))
445{}
446
447inline object::object(detail::new_non_null_reference p)
448    : object_base((PyObject*)p)
449{}
450
451inline PyObject* api::object_base::ptr() const
452{
453    return m_ptr;
454}
455
456//
457// Converter specialization implementations
458//
459namespace converter
460{
461  template <class T> struct object_manager_traits;
462 
463  template <>
464  struct object_manager_traits<object>
465  {
466      BOOST_STATIC_CONSTANT(bool, is_specialized = true);
467      static bool check(PyObject*) { return true; }
468     
469      static python::detail::new_non_null_reference adopt(PyObject* x)
470      {
471          return python::detail::new_non_null_reference(x);
472      }
473  };
474}
475
476inline PyObject* get_managed_object(object const& x, tag_t)
477{
478    return x.ptr();
479}
480
481}} // namespace boost::python
482
483# include <boost/python/slice_nil.hpp>
484
485#endif // OBJECT_CORE_DWA2002615_HPP
Note: See TracBrowser for help on using the repository browser.