]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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> | |
163 | 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> | |
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> | |
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> | |
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* | |
283 | get(object const& x, mpl::true_) | |
284 | { | |
285 | return python::incref(x.ptr()); | |
286 | } | |
287 | ||
288 | template <class T> | |
289 | static PyObject* | |
290 | 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* | |
301 | 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* | |
312 | 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: | |
343 | call_proxy(object target) : m_target(target) {} | |
344 | 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: | |
353 | kwds_proxy(object o = object()) : call_proxy(o) {} | |
354 | }; | |
355 | class args_proxy : public call_proxy | |
356 | { | |
357 | public: | |
358 | args_proxy(object o) : call_proxy(o) {} | |
359 | kwds_proxy operator* () const { return kwds_proxy(*this);} | |
360 | }; | |
361 | } | |
362 | ||
363 | template <typename U> | |
364 | 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> | |
371 | 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> | |
382 | 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> | |
396 | object api::object_operators<U>::contains(T const& key) const | |
397 | { | |
398 | return this->attr("__contains__")(object(key)); | |
399 | } | |
400 | ||
401 | ||
402 | inline object::object() | |
403 | : object_base(python::incref(Py_None)) | |
404 | {} | |
405 | ||
406 | // copy constructor without NULL checking, for efficiency | |
407 | inline api::object_base::object_base(object_base const& rhs) | |
408 | : m_ptr(python::incref(rhs.m_ptr)) | |
409 | {} | |
410 | ||
411 | inline api::object_base::object_base(PyObject* p) | |
412 | : m_ptr(p) | |
413 | {} | |
414 | ||
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 | ||
423 | inline api::object_base::~object_base() | |
424 | { | |
425 | assert( Py_REFCNT(m_ptr) > 0 ); | |
426 | Py_DECREF(m_ptr); | |
427 | } | |
428 | ||
429 | inline object::object(detail::borrowed_reference p) | |
430 | : object_base(python::incref((PyObject*)p)) | |
431 | {} | |
432 | ||
433 | inline object::object(detail::new_reference p) | |
434 | : object_base(expect_non_null((PyObject*)p)) | |
435 | {} | |
436 | ||
437 | inline object::object(detail::new_non_null_reference p) | |
438 | : object_base((PyObject*)p) | |
439 | {} | |
440 | ||
441 | inline PyObject* api::object_base::ptr() const | |
442 | { | |
443 | return m_ptr; | |
444 | } | |
445 | ||
446 | inline bool api::object_base::is_none() const | |
447 | { | |
448 | return (m_ptr == Py_None); | |
449 | } | |
450 | ||
451 | // | |
452 | // Converter specialization implementations | |
453 | // | |
454 | namespace converter | |
455 | { | |
456 | template <class T> struct object_manager_traits; | |
457 | ||
458 | template <> | |
459 | struct object_manager_traits<object> | |
460 | { | |
461 | BOOST_STATIC_CONSTANT(bool, is_specialized = true); | |
462 | static bool check(PyObject*) { return true; } | |
463 | ||
464 | static python::detail::new_non_null_reference adopt(PyObject* x) | |
465 | { | |
466 | return python::detail::new_non_null_reference(x); | |
467 | } | |
468 | #ifndef BOOST_PYTHON_NO_PY_SIGNATURES | |
469 | static PyTypeObject const *get_pytype() {return 0;} | |
470 | #endif | |
471 | }; | |
472 | } | |
473 | ||
474 | inline PyObject* get_managed_object(object const& x, tag_t) | |
475 | { | |
476 | return x.ptr(); | |
477 | } | |
478 | ||
479 | }} // namespace boost::python | |
480 | ||
481 | # include <boost/python/slice_nil.hpp> | |
482 | ||
483 | #endif // OBJECT_CORE_DWA2002615_HPP |