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