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 |
|
---|
43 | namespace boost { namespace python {
|
---|
44 |
|
---|
45 | namespace 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
|
---|
51 | namespace 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 | }
|
---|
406 | using api::object;
|
---|
407 | template <class T> struct extract;
|
---|
408 |
|
---|
409 | //
|
---|
410 | // implementation
|
---|
411 | //
|
---|
412 |
|
---|
413 | inline object::object()
|
---|
414 | : object_base(python::incref(Py_None))
|
---|
415 | {}
|
---|
416 |
|
---|
417 | // copy constructor without NULL checking, for efficiency
|
---|
418 | inline api::object_base::object_base(object_base const& rhs)
|
---|
419 | : m_ptr(python::incref(rhs.m_ptr))
|
---|
420 | {}
|
---|
421 |
|
---|
422 | inline api::object_base::object_base(PyObject* p)
|
---|
423 | : m_ptr(p)
|
---|
424 | {}
|
---|
425 |
|
---|
426 | inline 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 |
|
---|
434 | inline api::object_base::~object_base()
|
---|
435 | {
|
---|
436 | Py_DECREF(m_ptr);
|
---|
437 | }
|
---|
438 |
|
---|
439 | inline object::object(detail::borrowed_reference p)
|
---|
440 | : object_base(python::incref((PyObject*)p))
|
---|
441 | {}
|
---|
442 |
|
---|
443 | inline object::object(detail::new_reference p)
|
---|
444 | : object_base(expect_non_null((PyObject*)p))
|
---|
445 | {}
|
---|
446 |
|
---|
447 | inline object::object(detail::new_non_null_reference p)
|
---|
448 | : object_base((PyObject*)p)
|
---|
449 | {}
|
---|
450 |
|
---|
451 | inline PyObject* api::object_base::ptr() const
|
---|
452 | {
|
---|
453 | return m_ptr;
|
---|
454 | }
|
---|
455 |
|
---|
456 | //
|
---|
457 | // Converter specialization implementations
|
---|
458 | //
|
---|
459 | namespace 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 |
|
---|
476 | inline 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
|
---|