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