[857] | 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
|
---|