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