diff --git a/Jamfile b/Jamfile index 23d82c1b..b0993452 100644 --- a/Jamfile +++ b/Jamfile @@ -27,6 +27,7 @@ dll bpl src/converter/builtin_converters.cpp src/converter/callback.cpp src/object/iterator.cpp + src/object_protocol.cpp : $(BOOST_PYTHON_V2_PROPERTIES) BOOST_PYTHON_SOURCE diff --git a/include/boost/python/base_type_traits.hpp b/include/boost/python/base_type_traits.hpp new file mode 100755 index 00000000..cae9ebc2 --- /dev/null +++ b/include/boost/python/base_type_traits.hpp @@ -0,0 +1,36 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef BASE_TYPE_TRAITS_DWA2002614_HPP +# define BASE_TYPE_TRAITS_DWA2002614_HPP + +namespace boost { namespace python { + +namespace detail +{ + struct unspecialized {}; +} + +// Derive from unspecialized so we can detect whether traits are +// specialized +template struct base_type_traits + : detail::unspecialized +{}; + +template <> +struct base_type_traits +{ + typedef PyObject type; +}; + +template <> +struct base_type_traits +{ + typedef PyObject type; +}; + +}} // namespace boost::python + +#endif // BASE_TYPE_TRAITS_DWA2002614_HPP diff --git a/include/boost/python/cast.hpp b/include/boost/python/cast.hpp index 9408579a..1897fc60 100755 --- a/include/boost/python/cast.hpp +++ b/include/boost/python/cast.hpp @@ -9,38 +9,13 @@ # include # include # include +# include +# include namespace boost { namespace python { -template struct base_type_traits; - -template <> -struct base_type_traits -{ - typedef PyObject type; -}; - -template <> -struct base_type_traits -{ - typedef PyObject type; -}; - namespace detail { - typedef char* yes_convertible; - typedef int* no_convertible; - - typedef char* yes_python_object; - typedef int* no_python_object; - - template - struct convertible - { - static inline yes_convertible check(Target) { return 0; } - static inline no_convertible check(...) { return 0; } - }; - template inline Target* upcast(Target* p, yes_convertible) { diff --git a/include/boost/python/converter/arg_to_python.hpp b/include/boost/python/converter/arg_to_python.hpp index 78268fd0..e4a2bfaf 100755 --- a/include/boost/python/converter/arg_to_python.hpp +++ b/include/boost/python/converter/arg_to_python.hpp @@ -10,7 +10,11 @@ # include # include # include +# include # include +# include +# include +# include // Bring in specializations # include @@ -51,9 +55,27 @@ namespace detail static PyObject* get_object(Ptr p); }; + // Convert types that manage a Python object to_python + template + struct object_manager_arg_to_python + { + object_manager_arg_to_python(T const& x) : m_src(x) {} + + PyObject* get() const + { + return python::upcast(converter::get_managed_object(m_src)); + } + + private: + T const& m_src; + }; + template struct select_arg_to_python { + BOOST_STATIC_CONSTANT( + bool, manager = is_object_manager::value); + BOOST_STATIC_CONSTANT( bool, ptr = is_pointer::value); @@ -67,15 +89,19 @@ namespace detail typedef typename unwrap_pointer::type unwrapped_ptr; typedef typename mpl::select_type< - ptr - , pointer_deep_arg_to_python + manager + , object_manager_arg_to_python , typename mpl::select_type< - ptr_wrapper - , pointer_shallow_arg_to_python + ptr + , pointer_deep_arg_to_python , typename mpl::select_type< - ref_wrapper - , reference_arg_to_python - , value_arg_to_python + ptr_wrapper + , pointer_shallow_arg_to_python + , typename mpl::select_type< + ref_wrapper + , reference_arg_to_python + , value_arg_to_python + >::type >::type >::type >::type type; @@ -108,6 +134,39 @@ struct arg_to_python // namespace detail { + // reject_raw_object_ptr -- cause a compile-time error if the user + // should pass a raw Python object pointer + using python::detail::yes_convertible; + using python::detail::no_convertible; + using python::detail::unspecialized; + + template struct cannot_convert_raw_PyObject; + + template + struct reject_raw_object_helper + { + static void error(Convertibility) + { + cannot_convert_raw_PyObject::to_python_use_handle_instead(); + } + static void error(...) {} + }; + + template + inline void reject_raw_object_ptr(T*) + { + reject_raw_object_helper::error( + python::detail::convertible::check((T*)0)); + + typedef typename remove_cv::type value_type; + + reject_raw_object_helper::error( + python::detail::convertible::check( + (base_type_traits*)0 + )); + } + // --------- + template inline value_arg_to_python::value_arg_to_python(T const& x) : arg_to_python_base(&x, to_python_function::value) @@ -118,6 +177,7 @@ namespace detail inline pointer_deep_arg_to_python::pointer_deep_arg_to_python(Ptr x) : arg_to_python_base(x, pointee_to_python_function::value) { + detail::reject_raw_object_ptr((Ptr)0); } template @@ -131,14 +191,16 @@ namespace detail template inline reference_arg_to_python::reference_arg_to_python(T& x) - : handle<>(get_object(x)) + : handle<>(reference_arg_to_python::get_object(x)) { } template inline pointer_shallow_arg_to_python::pointer_shallow_arg_to_python(Ptr x) - : handle<>(get_object(x)) - {} + : handle<>(pointer_shallow_arg_to_python::get_object(x)) + { + detail::reject_raw_object_ptr((Ptr)0); + } template inline PyObject* pointer_shallow_arg_to_python::get_object(Ptr x) diff --git a/include/boost/python/converter/arg_to_python_base.hpp b/include/boost/python/converter/arg_to_python_base.hpp index 1e5fe191..a0ec7518 100755 --- a/include/boost/python/converter/arg_to_python_base.hpp +++ b/include/boost/python/converter/arg_to_python_base.hpp @@ -13,9 +13,18 @@ namespace boost { namespace python { namespace converter { namespace detail { - struct BOOST_PYTHON_DECL arg_to_python_base : handle<> + struct BOOST_PYTHON_DECL arg_to_python_base +# if !defined(BOOST_MSVC) || _MSC_FULL_VER != 13102140 + : handle<> +# endif { arg_to_python_base(void const volatile* source, to_python_function_t); +# if defined(BOOST_MSVC) && _MSC_FULL_VER == 13102140 + PyObject* get() const { return m_ptr.get(); } + PyObject* release() { return m_ptr.release(); } + private: + handle<> m_ptr; +# endif }; } diff --git a/include/boost/python/converter/builtin_converters.hpp b/include/boost/python/converter/builtin_converters.hpp index 77a78069..d8bce16b 100644 --- a/include/boost/python/converter/builtin_converters.hpp +++ b/include/boost/python/converter/builtin_converters.hpp @@ -105,7 +105,6 @@ BOOST_PYTHON_TO_PYTHON_BY_VALUE(float, PyFloat_FromDouble(x)) BOOST_PYTHON_TO_PYTHON_BY_VALUE(double, PyFloat_FromDouble(x)) BOOST_PYTHON_TO_PYTHON_BY_VALUE(long double, PyFloat_FromDouble(x)) BOOST_PYTHON_RETURN_TO_PYTHON_BY_VALUE(PyObject*, converter::do_return_to_python(x)) -BOOST_PYTHON_ARG_TO_PYTHON_BY_VALUE(PyObject*, converter::do_arg_to_python(x)) BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::complex, PyComplex_FromDoubles(x.real(), x.imag())) BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::complex, PyComplex_FromDoubles(x.real(), x.imag())) BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::complex, PyComplex_FromDoubles(x.real(), x.imag())) diff --git a/include/boost/python/converter/from_python.hpp b/include/boost/python/converter/from_python.hpp index 12740439..d2fb4db2 100644 --- a/include/boost/python/converter/from_python.hpp +++ b/include/boost/python/converter/from_python.hpp @@ -1,3 +1,4 @@ +#error obsolete // Copyright David Abrahams 2002. Permission to copy, use, // modify, sell and distribute this software is granted provided this // copyright notice appears in all copies. This software is provided diff --git a/include/boost/python/converter/object_manager.hpp b/include/boost/python/converter/object_manager.hpp new file mode 100755 index 00000000..93c394e2 --- /dev/null +++ b/include/boost/python/converter/object_manager.hpp @@ -0,0 +1,149 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef OBJECT_MANAGER_DWA2002614_HPP +# define OBJECT_MANAGER_DWA2002614_HPP + +# include +# include +# include +# include +# include + +namespace boost { namespace python { + +class object; + +}} + +namespace boost { namespace python { namespace converter { + +template +class is_object_manager +{ + BOOST_STATIC_CONSTANT(bool, hdl = is_handle::value); + BOOST_STATIC_CONSTANT(bool, borrowed = python::detail::is_borrowed_ptr::value); + public: + BOOST_STATIC_CONSTANT(bool, value = (hdl | borrowed)); +}; + +# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +template +struct is_reference_to_object_manager +{ + BOOST_STATIC_CONSTANT(bool, value = false); +}; + +template +struct is_reference_to_object_manager + : is_object_manager +{ +}; + +template +struct is_reference_to_object_manager + : is_object_manager +{ +}; + +template +struct is_reference_to_object_manager + : is_object_manager +{ +}; + +template +struct is_reference_to_object_manager + : is_object_manager +{ +}; +# else + +namespace detail +{ + typedef char (&yes_reference_to_object_manager)[1]; + typedef char (&no_reference_to_object_manager)[2]; + + template + struct is_object_manager_help + : mpl::select_type< + is_object_manager::value + , yes_reference_to_object_manager + , no_reference_to_object_manager> + { + }; + + template + struct is_reference_to_object_manager_helper + { + template + struct apply + { + static int x; + static no_reference_to_object_manager check(...); + }; + }; + + template + typename is_object_manager_help::type + is_object_manager_helper(int*, double, double, U&); + + template + typename is_object_manager_help::type + is_object_manager_helper(int*, int*, double, U const&); + + template + typename is_object_manager_help::type + is_object_manager_helper(int*, double, int*, U volatile&); + + template + typename is_object_manager_help::type + is_object_manager_helper(int*, int*, int*, U const volatile&); + + no_reference_to_object_manager is_object_manager_helper(...); +} + +template +struct is_reference_to_object_manager +{ + typedef typename mpl::select_type< + is_reference::value, int*, double>::type r_t; + typedef typename mpl::select_type< + python::detail::is_reference_to_const::value, int*, double>::type rc_t; + typedef typename mpl::select_type< + python::detail::is_reference_to_volatile::value, int*, double>::type rv_t; + + typedef typename mpl::select_type::value, T, int>::type value_t; + + static value_t sample_object; + + BOOST_STATIC_CONSTANT( + bool, value + = (sizeof(detail::is_object_manager_helper(r_t(),rc_t(),rv_t(),sample_object)) + == sizeof(detail::yes_reference_to_object_manager) + ) + ); +}; +# endif + +template +inline T* get_managed_object(handle const& h) +{ + return h.get(); +} + +template +inline T* get_managed_object(python::detail::borrowed const volatile* p) +{ + return (T*)p; +} + +// forward declaration needed because name lookup is bound by the +// definition context. +PyObject* get_managed_object(python::object const&); + +}}} // namespace boost::python::converter + +#endif // OBJECT_MANAGER_DWA2002614_HPP diff --git a/include/boost/python/converter/return_from_python.hpp b/include/boost/python/converter/return_from_python.hpp index 249bb6e3..cb16c888 100755 --- a/include/boost/python/converter/return_from_python.hpp +++ b/include/boost/python/converter/return_from_python.hpp @@ -7,6 +7,10 @@ # define RETURN_FROM_PYTHON_DWA200265_HPP # include +# include +# include +# include +# include namespace boost { namespace python { namespace converter { diff --git a/include/boost/python/detail/borrowed_ptr.hpp b/include/boost/python/detail/borrowed_ptr.hpp new file mode 100755 index 00000000..4e6d187a --- /dev/null +++ b/include/boost/python/detail/borrowed_ptr.hpp @@ -0,0 +1,56 @@ +#ifndef BORROWED_PTR_DWA20020601_HPP +# define BORROWED_PTR_DWA20020601_HPP +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. + +# include +#include + +namespace boost { namespace python { namespace detail { + +template class borrowed +{ + typedef T type; +}; + +# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +template +struct is_borrowed_ptr +{ + BOOST_STATIC_CONSTANT(bool, value = false); +}; + +template +struct is_borrowed_ptr*> +{ + BOOST_STATIC_CONSTANT(bool, value = true); +}; + +# else // no partial specialization + +typedef char (&yes_borrowed_ptr_t)[1]; +typedef char (&no_borrowed_ptr_t)[2]; + +no_borrowed_ptr_t is_borrowed_ptr_test(...); + +template +yes_borrowed_ptr_t is_borrowed_ptr_test(boost::type< borrowed* >); + +template +class is_borrowed_ptr +{ + public: + BOOST_STATIC_CONSTANT( + bool, value = ( + sizeof(detail::is_borrowed_ptr_test(boost::type())) + == sizeof(detail::yes_borrowed_ptr_t))); +}; + +# endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + +}}} // namespace boost::python::detail + +#endif // #ifndef BORROWED_PTR_DWA20020601_HPP diff --git a/include/boost/python/detail/convertible.hpp b/include/boost/python/detail/convertible.hpp new file mode 100755 index 00000000..2a4d5106 --- /dev/null +++ b/include/boost/python/detail/convertible.hpp @@ -0,0 +1,25 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef CONVERTIBLE_DWA2002614_HPP +# define CONVERTIBLE_DWA2002614_HPP + +// Supplies a runtime is_convertible check which can be used with tag +// dispatching to work around the Metrowerks Pro7 limitation with boost::is_convertible +namespace boost { namespace python { namespace detail { + +typedef char* yes_convertible; +typedef int* no_convertible; + +template +struct convertible +{ + static inline yes_convertible check(Target) { return 0; } + static inline no_convertible check(...) { return 0; } +}; + +}}} // namespace boost::python::detail + +#endif // CONVERTIBLE_DWA2002614_HPP diff --git a/include/boost/python/detail/indirect_traits.hpp b/include/boost/python/detail/indirect_traits.hpp index dd4502cc..ba184a7d 100644 --- a/include/boost/python/detail/indirect_traits.hpp +++ b/include/boost/python/detail/indirect_traits.hpp @@ -26,7 +26,7 @@ struct is_reference_to_const BOOST_STATIC_CONSTANT(bool, value = true); }; -# if defined(BOOST_MSVC) && _MSC_FULL_VER <= 13012108 // vc7.01 alpha workaround +# if defined(BOOST_MSVC) && _MSC_FULL_VER <= 13102140 // vc7.01 alpha workaround template struct is_reference_to_const { @@ -121,7 +121,7 @@ struct is_reference_to_volatile BOOST_STATIC_CONSTANT(bool, value = true); }; -# if defined(BOOST_MSVC) && _MSC_FULL_VER <= 13012108 // vc7.01 alpha workaround +# if defined(BOOST_MSVC) && _MSC_FULL_VER <= 13102140 // vc7.01 alpha workaround template struct is_reference_to_volatile { diff --git a/include/boost/python/detail/unwind_type.hpp b/include/boost/python/detail/unwind_type.hpp index 7d1fe390..878b6cc1 100644 --- a/include/boost/python/detail/unwind_type.hpp +++ b/include/boost/python/detail/unwind_type.hpp @@ -133,7 +133,7 @@ struct unwind_helper2 // why bother? template inline typename Generator::result_type -unwind_type(type*p = 0, Generator* = 0) +unwind_type(boost::type*p = 0, Generator* = 0) { BOOST_STATIC_CONSTANT(int, indirection = (is_pointer::value ? pointer_ : 0) diff --git a/include/boost/python/handle.hpp b/include/boost/python/handle.hpp index 912717e0..aa1412b3 100755 --- a/include/boost/python/handle.hpp +++ b/include/boost/python/handle.hpp @@ -9,44 +9,14 @@ # include # include # include +# include +# include +# include namespace boost { namespace python { -template -inline T* incref(T* p) -{ - Py_INCREF(python::upcast(p)); - return p; -} - -template -inline T* xincref(T* p) -{ - Py_XINCREF(python::upcast(p)); - return p; -} - -template -inline void decref(T* p) -{ - Py_DECREF(python::upcast(p)); -} - -template -inline void xdecref(T* p) -{ - Py_XDECREF(python::upcast(p)); -} - -template struct borrowed; template struct null_ok; -template -inline borrowed* borrow(T* p) -{ - return (borrowed*)p; -} - template inline null_ok* allow_null(T* p) { @@ -56,19 +26,19 @@ inline null_ok* allow_null(T* p) namespace detail { template - inline T* manage_ptr(borrowed >* p, int) + inline T* manage_ptr(detail::borrowed >* p, int) { return python::xincref((T*)p); } template - inline T* manage_ptr(null_ok >* p, int) + inline T* manage_ptr(null_ok >* p, int) { return python::xincref((T*)p); } template - inline T* manage_ptr(borrowed* p, long) + inline T* manage_ptr(detail::borrowed* p, long) { return python::incref(expect_non_null((T*)p)); } @@ -84,31 +54,9 @@ namespace detail { return expect_non_null(p); } - -#if 0 - template - struct handle_proxy - : handle_proxy::type> - { - typedef typename base_type_traits::type base_t; - handle_proxy(PyObject* p) - : handle_proxy(p) - {} - operator T*() const { return python::downcast(m_p); } - }; - - template <> - struct handle_proxy - { - handle_proxy(PyObject* p) : m_p(p) {} - operator PyObject*() const { return (PyObject*)m_p; } - private: - PyObject* m_p; - }; -#endif } -template +template class handle { typedef T* (handle::*bool_type); @@ -153,6 +101,7 @@ class handle } T* operator-> () const; + T& operator* () const; T* get() const; T* release(); @@ -168,6 +117,79 @@ class handle typedef handle type_handle; +// +// Converter specializations +// +template struct arg_from_python; +template <> +struct arg_from_python > +{ + typedef handle<> result_type; + + arg_from_python(PyObject*); + bool convertible() const; + handle<> operator()(PyObject* x) const; +}; + +template <> +struct arg_from_python const&> + : arg_from_python > +{ + arg_from_python(PyObject*); +}; + +namespace converter +{ + template struct return_from_python; + + template <> + struct return_from_python > + { + typedef handle<> result_type; + result_type operator()(PyObject* x) const; + }; +} + +// +// Compile-time introspection +// +# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +template +class is_handle +{ + public: + BOOST_STATIC_CONSTANT(bool, value = false); +}; + +template +class is_handle > +{ + public: + BOOST_STATIC_CONSTANT(bool, value = true); +}; +# else +namespace detail +{ + typedef char (&yes_handle_t)[1]; + typedef char (&no_handle_t)[2]; + + no_handle_t is_handle_test(...); + + template + yes_handle_t is_handle_test(boost::type< handle >); +} + +template +class is_handle +{ + public: + BOOST_STATIC_CONSTANT( + bool, value = ( + sizeof(detail::is_handle_test(boost::type())) + == sizeof(detail::yes_handle_t))); +}; +# endif + // // implementations // @@ -197,6 +219,12 @@ inline T* handle::operator->() const return m_p; } +template +inline T& handle::operator*() const +{ + return *m_p; +} + template inline T* handle::get() const { @@ -217,6 +245,35 @@ inline T* handle::release() return result; } +// +// Converter specialization implementation +// +inline arg_from_python >::arg_from_python(PyObject*) +{} + +inline bool arg_from_python >::convertible() const +{ + return true; +} + +inline handle<> arg_from_python >::operator()(PyObject* x) const +{ + return handle<>(python::borrowed(python::allow_null(x))); +} + +inline arg_from_python const&>::arg_from_python(PyObject*) + : arg_from_python >(0) +{} + +namespace converter +{ + inline handle<> + return_from_python >::operator()(PyObject* x) const + { + return handle<>(x); + } +} + }} // namespace boost::python diff --git a/include/boost/python/handle_fwd.hpp b/include/boost/python/handle_fwd.hpp new file mode 100755 index 00000000..afcce163 --- /dev/null +++ b/include/boost/python/handle_fwd.hpp @@ -0,0 +1,17 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef HANDLE_FWD_DWA2002615_HPP +# define HANDLE_FWD_DWA2002615_HPP + +# include + +namespace boost { namespace python { + +template class handle; + +}} // namespace boost::python + +#endif // HANDLE_FWD_DWA2002615_HPP diff --git a/include/boost/python/object.hpp b/include/boost/python/object.hpp new file mode 100755 index 00000000..6720298c --- /dev/null +++ b/include/boost/python/object.hpp @@ -0,0 +1,20 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef OBJECT_DWA2002612_HPP +# define OBJECT_DWA2002612_HPP + +# include +# include +# include + +namespace boost { namespace python { + +class string; +class type; + +}} // namespace boost::python + +#endif // OBJECT_DWA2002612_HPP diff --git a/include/boost/python/object/forward.hpp b/include/boost/python/object/forward.hpp index acae1173..cc23e94c 100644 --- a/include/boost/python/object/forward.hpp +++ b/include/boost/python/object/forward.hpp @@ -61,7 +61,7 @@ namespace detail no_reference_to_value_t is_reference_to_value_test(...); template - yes_reference_to_value_t is_reference_to_value_test(type< reference_to_value >); + yes_reference_to_value_t is_reference_to_value_test(boost::type< reference_to_value >); template struct unforwarder @@ -89,7 +89,7 @@ namespace detail public: BOOST_STATIC_CONSTANT( bool, value = ( - sizeof(is_reference_to_value_test(type())) + sizeof(is_reference_to_value_test(boost::type())) == sizeof(yes_reference_to_value_t))); }; } diff --git a/include/boost/python/object/iterator.hpp b/include/boost/python/object/iterator.hpp index 7e801f92..c9434a4f 100644 --- a/include/boost/python/object/iterator.hpp +++ b/include/boost/python/object/iterator.hpp @@ -174,7 +174,7 @@ namespace detail // Build and convert the iterator_range<>. return cr( iterator_range( - handle<>(python::borrow(arg0)) + handle<>(python::borrowed(arg0)) , get_start(x), get_finish(x))); } }; diff --git a/include/boost/python/object_attributes.hpp b/include/boost/python/object_attributes.hpp new file mode 100755 index 00000000..a7bd6a8e --- /dev/null +++ b/include/boost/python/object_attributes.hpp @@ -0,0 +1,81 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef OBJECT_ATTRIBUTES_DWA2002615_HPP +# define OBJECT_ATTRIBUTES_DWA2002615_HPP + +# include +# include +# include + +namespace boost { namespace python { + +namespace detail +{ + struct const_attribute_policies + { + static object get(object const& target, object const& key); + }; + + struct attribute_policies : const_attribute_policies + { + static object const& set(object const& target, object const& key, object const& value); + }; +} + +// +// implementation +// +inline object_attribute object::_(char const* name) +{ + return object_attribute(*this, object(name)); +} + +inline const_object_attribute object::_(char const* name) const +{ + return const_object_attribute(*this, object(name)); +} + +namespace detail +{ + inline object const_attribute_policies::get(object const& target, object const& key) + { + return python::getattr(target, key); + } + + inline object const& attribute_policies::set( + object const& target + , object const& key + , object const& value) + { + python::setattr(target, key, value); + return value; + } +} + +namespace converter +{ + // These specializations are a lie; the proxies do not directly + // manage an object. What actually happens is that the implicit + // conversion to object takes hold and its conversion to_python is + // used. That's OK in part because the object temporary *is* + // actually managing the object during the duration of the + // conversion. + template <> + struct is_object_manager + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + + template <> + struct is_object_manager + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; +} + +}} // namespace boost::python + +#endif // OBJECT_ATTRIBUTES_DWA2002615_HPP diff --git a/include/boost/python/object_core.hpp b/include/boost/python/object_core.hpp new file mode 100755 index 00000000..80ebf2c0 --- /dev/null +++ b/include/boost/python/object_core.hpp @@ -0,0 +1,286 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef OBJECT_CORE_DWA2002615_HPP +# define OBJECT_CORE_DWA2002615_HPP +# include +# include +# include +# include + +namespace boost { namespace python { + +// This file contains the definition of the object class and enough to +// construct/copy it, but not enough to do operations like +// attribute/item access or addition. + +template class proxy; +namespace detail +{ + struct const_attribute_policies; + struct attribute_policies; + struct const_item_policies; + struct item_policies; +} +typedef proxy const_object_attribute; +typedef proxy object_attribute; +typedef proxy const_object_item; +typedef proxy object_item; + +class object +{ +# if !defined(BOOST_MSVC) || BOOST_MSVC > 1200 + typedef object const& self_cref; +# else + typedef object self_cref; +# endif + public: +# ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING + // copy constructor without NULL checking, for efficiency + object(object const&); +# endif + + // explicit conversion from any C++ object to Python + template + explicit object(T const& x) + : m_ptr( + python::borrowed( + python::allow_null( // null check is already done + converter::arg_to_python(x).get()) + ) + ) + { + } + + // capture this case explicitly to handle string + // literals. Otherwise, they get deduced as char[N]const& above + // and conversion fails at runtime. + explicit object(char const* x) + : m_ptr( + python::borrowed( + python::allow_null( // null check is already done + converter::arg_to_python(x).get()) + ) + ) + { + + } + + // Throw error_already_set() if the handle is null. + explicit object(handle<> const&); + + // Attribute access via x._("attribute_name") + const_object_attribute _(char const*) const; + object_attribute _(char const*); + + object operator()() const + { + return object(call >(m_ptr.get())); + } + +# ifndef BOOST_PYTHON_GENERATE_CODE +# include +# endif + +# define BOOST_PYTHON_OBJECT_CALL(nargs,ignored) \ + template \ + object operator()(BOOST_PYTHON_ENUM_PARAMS2(nargs, (A,const& a))) const \ + { \ + return object(call >(&**this, BOOST_PP_ENUM_PARAMS(nargs, a))); \ + } + + BOOST_PYTHON_REPEAT_ARITY_2ND(BOOST_PYTHON_OBJECT_CALL, ignored) + + // truth value testing + typedef handle<> (object::*bool_type); + operator bool_type() const; + bool operator!() const; // needed for vc6 + + // item access + const_object_item operator[](self_cref) const; + object_item operator[](self_cref); + + template + const_object_item operator[](T const& key) const + { + return (*this)[object(key)]; + } + + template + object_item operator[](T const& key) + { + return (*this)[object(key)]; + } + + // Underlying object access + PyObject* operator->() const; + PyObject& operator*() const; + + public: // implementation detail -- for internal use only + object(null_ok >*); + object(detail::borrowed >*); + object(detail::borrowed*); + class new_pyobject_reference; + object(new_pyobject_reference*); + + private: + handle<> m_ptr; +}; + +// +// Converter Specializations +// +template struct arg_from_python; + +template <> +struct arg_from_python +{ + typedef object result_type; + + arg_from_python(PyObject*); + bool convertible() const; + object operator()(PyObject* x) const; +}; + +template <> +struct arg_from_python + : arg_from_python +{ + arg_from_python(PyObject*); +}; + +template <> +struct arg_from_python +{ + typedef object& result_type; + + arg_from_python(PyObject*); + bool convertible() const; + object& operator()(PyObject* x) const; + private: + mutable object m_result; +}; + +namespace converter +{ + template struct is_object_manager; + + template <> + struct is_object_manager + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + + template struct return_from_python; + template <> + struct return_from_python + { + typedef object result_type; + result_type operator()(PyObject* x) const; + }; +} + +// +// implementation +// + +inline object::object(handle<> const& x) + : m_ptr(python::borrowed(x.get())) +{} + +# ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING +// copy constructor without NULL checking, for efficiency +inline object::object(object const& rhs) + : m_ptr(python::allow_null(python::borrowed(&*rhs))) +{} +# endif + +inline object::object(null_ok >* p) + : m_ptr(p) +{} + +inline object::object(detail::borrowed >* p) + : m_ptr(p) +{} + +inline object::object(detail::borrowed* p) + : m_ptr(p) +{} + +inline object::object(object::new_pyobject_reference* p) + : m_ptr((PyObject*)p) +{} + +inline PyObject* object::operator->() const +{ + return m_ptr.operator->(); +} + +inline PyObject& object::operator*() const +{ + return *m_ptr; +} + +inline object::operator object::bool_type() const +{ + return PyObject_IsTrue(&**this) ? &object::m_ptr : 0; +} + +inline bool object::operator!() const +{ + return !PyObject_IsTrue(&**this); +} + +// +// Converter speciaization implementations +// +inline arg_from_python::arg_from_python(PyObject*) +{} + +inline bool arg_from_python::convertible() const +{ + return true; +} + +inline object arg_from_python::operator()(PyObject* x) const +{ + return object(python::borrowed(python::allow_null(x))); +} + +inline arg_from_python::arg_from_python(PyObject*) + : arg_from_python(0) +{} + +inline arg_from_python::arg_from_python(PyObject* x) + : m_result(python::allow_null(python::borrowed(x))) +{} + +inline bool arg_from_python::convertible() const +{ + return true; +} + +inline object& arg_from_python::operator()(PyObject* x) const +{ + return m_result; +} + +namespace converter +{ + inline object + return_from_python::operator()(PyObject* x) const + { + return object((object::new_pyobject_reference*)x); + } + + inline PyObject* get_managed_object(object const& x) + { + return &*x; + } +} + +}} // namespace boost::python + +#endif // OBJECT_CORE_DWA2002615_HPP diff --git a/include/boost/python/object_items.hpp b/include/boost/python/object_items.hpp new file mode 100755 index 00000000..27233c24 --- /dev/null +++ b/include/boost/python/object_items.hpp @@ -0,0 +1,81 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef OBJECT_ITEMS_DWA2002615_HPP +# define OBJECT_ITEMS_DWA2002615_HPP + +# include +# include +# include + +namespace boost { namespace python { + +namespace detail +{ + struct const_item_policies + { + static object get(object const& target, object const& key); + }; + + struct item_policies : const_item_policies + { + static object const& set(object const& target, object const& key, object const& value); + }; +} + +// +// implementation +// +inline object_item object::operator[](object::self_cref key) +{ + return object_item(*this, key); +} + +inline const_object_item object::operator[](object::self_cref key) const +{ + return const_object_item(*this, key); +} + +namespace detail +{ + inline object const_item_policies::get(object const& target, object const& key) + { + return python::getitem(target, key); + } + + inline object const& item_policies::set( + object const& target + , object const& key + , object const& value) + { + python::setitem(target, key, value); + return value; + } +} + +namespace converter +{ + // These specializations are a lie; the proxies do not directly + // manage an object. What actually happens is that the implicit + // conversion to object takes hold and its conversion to_python is + // used. That's OK in part because the object temporary *is* + // actually managing the object during the duration of the + // conversion. + template <> + struct is_object_manager + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + + template <> + struct is_object_manager + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; +} + +}} // namespace boost::python + +#endif // OBJECT_ITEMS_DWA2002615_HPP diff --git a/include/boost/python/object_protocol.hpp b/include/boost/python/object_protocol.hpp new file mode 100755 index 00000000..e9b47bad --- /dev/null +++ b/include/boost/python/object_protocol.hpp @@ -0,0 +1,45 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef OBJECT_PROTOCOL_DWA2002615_HPP +# define OBJECT_PROTOCOL_DWA2002615_HPP + +# include +# include +# include +# include + +namespace boost { namespace python { + +template +inline object getattr(Target const& target, Key const& key) +{ + return getattr(object(target), object(key)); +} + + +template +inline void setattr(object const& target, Key const& key, Value const& value) +{ + return setattr(target, object(key), object(value)); +} + +template +inline object getitem(Target const& target, Key const& key) +{ + return getitem(object(target), object(key)); +} + + +template +inline void setitem(object const& target, Key const& key, Value const& value) +{ + return setitem(target, object(key), object(value)); +} + + +}} // namespace boost::python + +#endif // OBJECT_PROTOCOL_DWA2002615_HPP diff --git a/include/boost/python/object_protocol_core.hpp b/include/boost/python/object_protocol_core.hpp new file mode 100755 index 00000000..adbd593f --- /dev/null +++ b/include/boost/python/object_protocol_core.hpp @@ -0,0 +1,20 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef OBJECT_PROTOCOL_CORE_DWA2002615_HPP +# define OBJECT_PROTOCOL_CORE_DWA2002615_HPP + +namespace boost { namespace python { + +class object; + +BOOST_PYTHON_DECL object getattr(object const& target, object const& key); +BOOST_PYTHON_DECL void setattr(object const& target, object const& key, object const& value); +BOOST_PYTHON_DECL object getitem(object const& target, object const& key); +BOOST_PYTHON_DECL void setitem(object const& target, object const& key, object const& value); + +}} // namespace boost::python + +#endif // OBJECT_PROTOCOL_CORE_DWA2002615_HPP diff --git a/include/boost/python/preprocessed/object_call.hpp b/include/boost/python/preprocessed/object_call.hpp new file mode 100755 index 00000000..e3d605cb --- /dev/null +++ b/include/boost/python/preprocessed/object_call.hpp @@ -0,0 +1,101 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef OBJECT_CALL_DWA2002612_HPP +# define OBJECT_CALL_DWA2002612_HPP + +template +object +operator()(A0 const&a0)const +{ + return call(&**this,a0); +} +template +object +operator()(A0 const&a0,A1 const&a1)const +{ + return call(&**this,a0,a1); +} +template +object +operator()(A0 const&a0,A1 const&a1,A2 const&a2)const +{ + return call(&**this,a0,a1,a2); +} +template +object +operator()(A0 const&a0,A1 const&a1,A2 const&a2,A3 const&a3)const +{ + return call(&**this,a0,a1,a2,a3); +} +template +object +operator()(A0 const&a0,A1 const&a1,A2 const&a2,A3 const&a3,A4 const&a4)const +{ + return call(&**this,a0,a1,a2,a3,a4); +} +template +object +operator()(A0 const&a0,A1 const&a1,A2 const&a2,A3 const&a3,A4 const&a4,A5 const&a5)const +{ + return call(&**this,a0,a1,a2,a3,a4,a5); +} +template +object +operator()(A0 const&a0,A1 const&a1,A2 const&a2,A3 const&a3,A4 const&a4,A5 const&a5,A6 const&a6)const +{ + return call(&**this,a0,a1,a2,a3,a4,a5,a6); +} +template +object +operator()(A0 const&a0,A1 const&a1,A2 const&a2,A3 const&a3,A4 const&a4,A5 const&a5,A6 const&a6,A7 const&a7)const +{ + return call(&**this,a0,a1,a2,a3,a4,a5,a6,a7); +} +template +object +operator()(A0 const&a0,A1 const&a1,A2 const&a2,A3 const&a3,A4 const&a4,A5 const&a5,A6 const&a6,A7 const&a7,A8 const&a8)const +{ + return call(&**this,a0,a1,a2,a3,a4,a5,a6,a7,a8); +} +template +object +operator()(A0 const&a0,A1 const&a1,A2 const&a2,A3 const&a3,A4 const&a4,A5 const&a5,A6 const&a6,A7 const&a7,A8 const&a8,A9 const&a9)const +{ + return call(&**this,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9); +} +template +object +operator()(A0 const&a0,A1 const&a1,A2 const&a2,A3 const&a3,A4 const&a4,A5 const&a5,A6 const&a6,A7 const&a7,A8 const&a8,A9 const&a9,A10 const&a10)const +{ + return call(&**this,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10); +} +template +object +operator()(A0 const&a0,A1 const&a1,A2 const&a2,A3 const&a3,A4 const&a4,A5 const&a5,A6 const&a6,A7 const&a7,A8 const&a8,A9 const&a9,A10 const&a10,A11 const&a11)const +{ + return call(&**this,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11); +} +template +object +operator()(A0 const&a0,A1 const&a1,A2 const&a2,A3 const&a3,A4 const&a4,A5 const&a5,A6 const&a6,A7 const&a7,A8 const&a8,A9 const&a9,A10 const&a10,A11 const&a11,A12 const&a12)const +{ + return call(&**this,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12); +} +template +object +operator()(A0 const&a0,A1 const&a1,A2 const&a2,A3 const&a3,A4 const&a4,A5 const&a5,A6 const&a6,A7 const&a7,A8 const&a8,A9 const&a9,A10 const&a10,A11 const&a11,A12 const&a12,A13 const&a13)const +{ + return call(&**this,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13); +} +template +object +operator()(A0 const&a0,A1 const&a1,A2 const&a2,A3 const&a3,A4 const&a4,A5 const&a5,A6 const&a6,A7 const&a7,A8 const&a8,A9 const&a9,A10 const&a10,A11 const&a11,A12 const&a12,A13 const&a13,A14 const&a14)const +{ + return call(&**this,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14); +} + + +#endif // OBJECT_CALL_DWA2002612_HPP diff --git a/include/boost/python/proxy.hpp b/include/boost/python/proxy.hpp new file mode 100755 index 00000000..46476f2d --- /dev/null +++ b/include/boost/python/proxy.hpp @@ -0,0 +1,129 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef PROXY_DWA2002615_HPP +# define PROXY_DWA2002615_HPP +# include + +namespace boost { namespace python { + +class object; + +template +class proxy +{ +# if !defined(BOOST_MSVC) || BOOST_MSVC > 1200 + typedef proxy const& copy_ctor_self; +# else + typedef proxy copy_ctor_self; +# endif + public: + operator object() const; + + // to support a[b] = c[d] + proxy& operator=(copy_ctor_self); + + template + inline proxy& operator=(T const& rhs) + { + Policies::set(m_target, m_key, python::object(rhs)); + return *this; + } + +# define BOOST_PYTHON_PROXY_ASSIGN_DECL(op) \ + object operator op (object const&); \ + \ + template \ + object operator op (T const& rhs) \ + { \ + return *this op python::object(rhs); \ + } + +// BOOST_PYTHON_PROXY_ASSIGN_DECL(=) + BOOST_PYTHON_PROXY_ASSIGN_DECL(+=) + BOOST_PYTHON_PROXY_ASSIGN_DECL(-=) + BOOST_PYTHON_PROXY_ASSIGN_DECL(*=) + BOOST_PYTHON_PROXY_ASSIGN_DECL(/=) + BOOST_PYTHON_PROXY_ASSIGN_DECL(%=) + BOOST_PYTHON_PROXY_ASSIGN_DECL(<<=) + BOOST_PYTHON_PROXY_ASSIGN_DECL(>>=) + BOOST_PYTHON_PROXY_ASSIGN_DECL(&=) + BOOST_PYTHON_PROXY_ASSIGN_DECL(^=) + BOOST_PYTHON_PROXY_ASSIGN_DECL(|=) +# undef BOOST_PYTHON_PROXY_ASSIGN_DECL + + // truth value testing + operator object::bool_type() const; + bool operator!() const; // needed for vc6 + + private: + friend class object; + proxy(object const& target, object const& key); + + private: + object m_target; + object m_key; +}; + +// +// implementation +// + +template +inline proxy::proxy(object const& target, object const& key) + : m_target(target), m_key(key) +{} + +template +inline proxy::operator object() const +{ + return Policies::get(m_target, m_key); +} + +// to support a[b] = c[d] +template +inline proxy& proxy::operator=(typename proxy::copy_ctor_self rhs) +{ + return *this = python::object(rhs); +} + +# define BOOST_PYTHON_PROXY_ASSIGN_DEF(op) \ +template \ +inline object proxy::operator op(object const& other) \ +{ \ + return Policies::set( \ + m_target, m_key \ + , Policies::get(m_target,m_key) op other); \ +} + +BOOST_PYTHON_PROXY_ASSIGN_DEF(+=) +BOOST_PYTHON_PROXY_ASSIGN_DEF(-=) +BOOST_PYTHON_PROXY_ASSIGN_DEF(*=) +BOOST_PYTHON_PROXY_ASSIGN_DEF(/=) +BOOST_PYTHON_PROXY_ASSIGN_DEF(%=) +BOOST_PYTHON_PROXY_ASSIGN_DEF(<<=) +BOOST_PYTHON_PROXY_ASSIGN_DEF(>>=) +BOOST_PYTHON_PROXY_ASSIGN_DEF(&=) +BOOST_PYTHON_PROXY_ASSIGN_DEF(^=) +BOOST_PYTHON_PROXY_ASSIGN_DEF(|=) + +# undef BOOST_PYTHON_PROXY_ASSIGN_DEF + + +template +inline proxy::operator object::bool_type() const +{ + return python::object(*this); +} + +template +inline bool proxy::operator!() const +{ + return !python::object(*this); +} + +}} // namespace boost::python + +#endif // PROXY_DWA2002615_HPP diff --git a/include/boost/python/refcount.hpp b/include/boost/python/refcount.hpp new file mode 100755 index 00000000..dce6b266 --- /dev/null +++ b/include/boost/python/refcount.hpp @@ -0,0 +1,42 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef REFCOUNT_DWA2002615_HPP +# define REFCOUNT_DWA2002615_HPP + +# include +# include + +namespace boost { namespace python { + +template +inline T* incref(T* p) +{ + Py_INCREF(python::upcast(p)); + return p; +} + +template +inline T* xincref(T* p) +{ + Py_XINCREF(python::upcast(p)); + return p; +} + +template +inline void decref(T* p) +{ + Py_DECREF(python::upcast(p)); +} + +template +inline void xdecref(T* p) +{ + Py_XDECREF(python::upcast(p)); +} + +}} // namespace boost::python + +#endif // REFCOUNT_DWA2002615_HPP diff --git a/include/boost/python/to_python_value.hpp b/include/boost/python/to_python_value.hpp index 8f3b0e22..ea9e892e 100644 --- a/include/boost/python/to_python_value.hpp +++ b/include/boost/python/to_python_value.hpp @@ -10,34 +10,84 @@ # include # include # include +# include +# include +# include +# include namespace boost { namespace python { -template -struct to_python_value +namespace detail { - typedef typename add_reference< - typename add_const::type - >::type argument_type; + template + struct object_manager_to_python_value + { + typedef typename add_reference< + typename add_const::type + >::type argument_type; - static bool convertible(); - PyObject* operator()(argument_type) const; -}; + static bool convertible(); + PyObject* operator()(argument_type) const; + }; - -template -bool to_python_value::convertible() -{ - // if this assert fires, our static variable hasn't been set up yet. - return converter::to_python_function::value != 0; + + template + struct registry_to_python_value + { + typedef typename add_reference< + typename add_const::type + >::type argument_type; + + static bool convertible(); + PyObject* operator()(argument_type) const; + }; } template -PyObject* to_python_value::operator()(argument_type x) const +struct to_python_value + : mpl::select_type< + boost::type_traits::ice_or< + converter::is_object_manager::value + , converter::is_reference_to_object_manager::value + >::value + + , detail::object_manager_to_python_value + , detail::registry_to_python_value + >::type { - // This might be further optimized on platforms which dynamically - // link without specific imports/exports - return converter::to_python_function::value(&x); +}; + +// +// implementation +// +namespace detail +{ + template + inline bool registry_to_python_value::convertible() + { + return converter::to_python_function::value != 0; + } + + template + inline PyObject* registry_to_python_value::operator()(argument_type x) const + { + return converter::to_python_function::value(&x); + } + + template + inline bool object_manager_to_python_value::convertible() + { + return true; + } + + template + inline PyObject* object_manager_to_python_value::operator()(argument_type x) const + { + return python::upcast( + python::xincref( + converter::get_managed_object(x)) + ); + } } }} // namespace boost::python diff --git a/src/converter/callback.cpp b/src/converter/callback.cpp index 573e38f9..e07b4869 100644 --- a/src/converter/callback.cpp +++ b/src/converter/callback.cpp @@ -35,7 +35,11 @@ namespace detail arg_to_python_base::arg_to_python_base( void const volatile* source, to_python_function_t converter) +# if !defined(BOOST_MSVC) || _MSC_FULL_VER != 13102140 : handle<>(convert(source, converter)) +# else + : m_ptr(convert(source, converter)) +# endif { } diff --git a/src/module.cpp b/src/module.cpp index e5d996cc..f7edf39e 100644 --- a/src/module.cpp +++ b/src/module.cpp @@ -14,7 +14,7 @@ namespace boost { namespace python { namespace detail { module_base::module_base(const char* name) : m_module( - borrow(Py_InitModule(const_cast(name), initial_methods)) + python::borrowed(Py_InitModule(const_cast(name), initial_methods)) ) { } diff --git a/src/object/class.cpp b/src/object/class.cpp index cfea075f..a64b811d 100644 --- a/src/object/class.cpp +++ b/src/object/class.cpp @@ -110,7 +110,7 @@ namespace objects if (PyType_Ready(&class_metatype_object)) return type_handle(); } - return type_handle(borrow(&class_metatype_object)); + return type_handle(borrowed(&class_metatype_object)); } extern "C" { @@ -181,7 +181,7 @@ namespace objects if (PyType_Ready(&class_type_object)) return type_handle(); } - return type_handle(borrow(&class_type_object)); + return type_handle(borrowed(&class_type_object)); } BOOST_PYTHON_DECL void* diff --git a/src/object_protocol.cpp b/src/object_protocol.cpp new file mode 100755 index 00000000..c04a8da2 --- /dev/null +++ b/src/object_protocol.cpp @@ -0,0 +1,35 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. + +#include +#include +#include + +namespace boost { namespace python { + +object getattr(object const& target, object const& key) +{ + return object((object::new_pyobject_reference*)PyObject_GetAttr(&*target, &*key)); +} + +void setattr(object const& target, object const& key, object const& value) +{ + if (PyObject_SetAttr(&*target, &*key, &*value) == -1) + throw_error_already_set(); +} + +object getitem(object const& target, object const& key) +{ + return object((object::new_pyobject_reference*)PyObject_GetItem(&*target, &*key)); +} + +void setitem(object const& target, object const& key, object const& value) +{ + if (PyObject_SetItem(&*target, &*key, &*value) == -1) + throw_error_already_set(); +} + +}} // namespace boost::python diff --git a/src/objects2.cpp b/src/objects2.cpp index 5ec410ab..699b21df 100755 --- a/src/objects2.cpp +++ b/src/objects2.cpp @@ -18,7 +18,7 @@ namespace boost { namespace python { objects_base::objects_base(handle<> const& p) - : m_p(borrow(p.get())) // Do the null check here + : m_p(borrowed(p.get())) // Do the null check here {} // Return a reference to the held object @@ -72,7 +72,7 @@ std::size_t tuple_base::size() const handle<> tuple_base::operator[](std::size_t pos) const { - return handle<>(borrow(PyTuple_GetItem(get(), static_cast(pos)))); + return handle<>(borrowed(PyTuple_GetItem(get(), static_cast(pos)))); } void tuple_base::set_item(std::size_t pos, const handle<>& rhs) @@ -146,7 +146,7 @@ const char* string::c_str() const void string::intern() { // UNTESTED!! - *this = string(handle<>(borrow(PyString_InternFromString(c_str())))); + *this = string(handle<>(borrowed(PyString_InternFromString(c_str())))); } string& string::operator*=(unsigned int repeat_count) @@ -214,7 +214,7 @@ handle<> dictionary_base::get_item(const handle<>& key, const handle<>& default_ if (value_or_null == 0 && !PyErr_Occurred()) return default_; else - return handle<>(borrow(value_or_null)); // Will throw if there was another error + return handle<>(borrowed(value_or_null)); // Will throw if there was another error } void dictionary_base::set_item(const handle<>& key, const handle<>& value) @@ -310,7 +310,7 @@ std::size_t list_base::size() const handle<> list_base::operator[](std::size_t pos) const { - return handle<>(borrow(PyList_GetItem(get(), pos))); + return handle<>(borrowed(PyList_GetItem(get(), pos))); } list_proxy list_base::operator[](std::size_t pos) @@ -370,12 +370,12 @@ const handle<>& list_proxy::operator=(const handle<>& rhs) list_proxy::operator handle<>() const { - return handle<>(borrow(PyList_GetItem(m_list.get(), m_index))); + return handle<>(borrowed(PyList_GetItem(m_list.get(), m_index))); } handle<> list_base::get_item(std::size_t pos) const { - return handle<>(borrow(PyList_GetItem(this->get(), pos))); + return handle<>(borrowed(PyList_GetItem(this->get(), pos))); } void list_base::set_item(std::size_t pos, const handle<>& rhs) diff --git a/test/Jamfile b/test/Jamfile index c0459022..b54bb723 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -1,8 +1,11 @@ subproject libs/python/test ; # bring in the rules for python -SEARCH on python.jam = $(BOOST_BUILD_PATH) ; -include python.jam ; +SEARCH on python.jam = $(BOOST_BUILD_PATH) ; +include python.jam ; +# bring in rules for testing +SEARCH on testing.jam = $(BOOST_BUILD_PATH) ; +include testing.jam ; local PYTHON_V1_PROPERTIES = $(PYTHON_PROPERTIES) ; local PYTHON_PROPERTIES = $(BOOST_PYTHON_V2_PROPERTIES) ; @@ -58,6 +61,7 @@ bpl-test builtin_converters : test_builtin_converters.py test_builtin_converters bpl-test test_pointer_adoption ; bpl-test operators ; bpl-test callbacks ; +bpl-test object ; bpl-test virtual_functions ; bpl-test back_reference ; bpl-test implicit ; @@ -76,44 +80,44 @@ if $(TEST_BIENSTMAN_NON_BUGS) } # --- unit tests of library components --- -unit-test indirect_traits_test - : indirect_traits_test.cpp : $(BOOST_ROOT) ; -unit-test destroy_test - : destroy_test.cpp : $(BOOST_ROOT) ; -unit-test pointer_type_id_test - : pointer_type_id_test.cpp : $(BOOST_ROOT) ; +run indirect_traits_test.cpp ; +run destroy_test.cpp ; +run pointer_type_id_test.cpp ; +run member_function_cast.cpp ; +run bases.cpp ; +run if_else.cpp ; +run pointee.cpp ; +run result.cpp ; +compile borrowed.cpp : $(PYTHON_PROPERTIES) ; +compile object_manager.cpp : $(PYTHON_PROPERTIES) ; -unit-test member_function_cast - : member_function_cast.cpp : $(BOOST_ROOT) ; +run upcast.cpp + : # command-line args + : # input files + : [ difference $(PYTHON_PROPERTIES) : BOOST_PYTHON_DYNAMIC_LIB ] + BOOST_PYTHON_STATIC_LIB + ; -unit-test bases - : bases.cpp : $(BOOST_ROOT) ; - -unit-test if_else - : if_else.cpp : $(BOOST_ROOT) ; - -unit-test pointee - : pointee.cpp : $(BOOST_ROOT) ; - -unit-test result - : result.cpp : $(BOOST_ROOT) ; - -unit-test upcast - : upcast.cpp - : $(BOOST_ROOT) BOOST_PYTHON_STATIC_LIB $(PYTHON_PROPERTIES) ; - -unit-test select_holder - : select_holder.cpp - : $(BOOST_ROOT) BOOST_PYTHON_STATIC_LIB $(PYTHON_PROPERTIES) -; - -unit-test select_from_python_test - : select_from_python_test.cpp - ../src/converter/type_id.cpp - - : $(BOOST_ROOT) - [ difference $(PYTHON_PROPERTIES) : BOOST_PYTHON_DYNAMIC_LIB ] +run select_holder.cpp + : # command-line args + : # input files + : [ difference $(PYTHON_PROPERTIES) : BOOST_PYTHON_DYNAMIC_LIB ] BOOST_PYTHON_STATIC_LIB ; +run select_from_python_test.cpp ../src/converter/type_id.cpp + : # command-line args + : # input files + : [ difference $(PYTHON_PROPERTIES) : BOOST_PYTHON_DYNAMIC_LIB ] + BOOST_PYTHON_STATIC_LIB + ; + +if $(TEST_EXPECTED_FAILURES) +{ + compile-fail ./raw_pyobject_fail1.cpp : $(PYTHON_PROPERTIES) ; + compile-fail ./raw_pyobject_fail2.cpp : $(PYTHON_PROPERTIES) ; + compile-fail ./object_fail1.cpp : $(PYTHON_PROPERTIES) ; +} + + diff --git a/test/borrowed.cpp b/test/borrowed.cpp new file mode 100755 index 00000000..b46dafb0 --- /dev/null +++ b/test/borrowed.cpp @@ -0,0 +1,33 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#include +#include + +using namespace boost::python; + +template +void assert_borrowed_ptr(T const& x) +{ + BOOST_STATIC_ASSERT(boost::python::detail::is_borrowed_ptr::value); +} + +template +void assert_not_borrowed_ptr(T const& x) +{ + BOOST_STATIC_ASSERT(!boost::python::detail::is_borrowed_ptr::value); +} + +int main() +{ + assert_borrowed_ptr(borrowed((PyObject*)0)); + assert_borrowed_ptr(borrowed((PyTypeObject*)0)); + assert_borrowed_ptr((detail::borrowed const*)0); + assert_borrowed_ptr((detail::borrowed volatile*)0); + assert_borrowed_ptr((detail::borrowed const volatile*)0); + assert_not_borrowed_ptr((PyObject*)0); + assert_not_borrowed_ptr(0); + return 0; +} diff --git a/test/callbacks.cpp b/test/callbacks.cpp index 4d8ead2c..6be5a782 100644 --- a/test/callbacks.cpp +++ b/test/callbacks.cpp @@ -11,6 +11,7 @@ #include #include #include +#include using namespace boost::python; @@ -51,12 +52,12 @@ void apply_void_X_ref(PyObject* f, X& x) call(f, boost::ref(x)); } -X& apply_X_ref_pyobject(PyObject* f, PyObject* obj) +X& apply_X_ref_handle(PyObject* f, handle<> obj) { return call(f, obj); } -X* apply_X_ptr_pyobject(PyObject* f, PyObject* obj) +X* apply_X_ptr_handle_cref(PyObject* f, handle<> const& obj) { return call(f, obj); } @@ -83,7 +84,7 @@ char const* apply_cstring_cstring(PyObject* f, char const* s) char const* apply_cstring_pyobject(PyObject* f, PyObject* s) { - return call(f, s); + return call(f, borrowed(s)); } char apply_char_char(PyObject* f, char c) @@ -96,11 +97,25 @@ char const* apply_to_string_literal(PyObject* f) return call(f, "hello, world"); } +handle<> apply_to_own_type(handle<> x) +{ + // Tests that we can return handle<> from a callback and that we + // can pass arbitrary handle. + return call >(x.get(), type_handle(borrowed(x->ob_type))); +} + +object apply_object_object(PyObject* f, object x) +{ + return call(f, x); +} + int X::counter; BOOST_PYTHON_MODULE_INIT(callbacks_ext) { boost::python::module("callbacks_ext") + .def("apply_object_object", apply_object_object) + .def("apply_to_own_type", apply_to_own_type) .def("apply_int_int", apply_int_int) .def("apply_void_int", apply_void_int) .def("apply_X_X", apply_X_X) @@ -109,10 +124,10 @@ BOOST_PYTHON_MODULE_INIT(callbacks_ext) .def("apply_void_X_ptr", apply_void_X_ptr) .def("apply_void_X_deep_ptr", apply_void_X_deep_ptr) - .def("apply_X_ptr_pyobject", apply_X_ptr_pyobject + .def("apply_X_ptr_handle_cref", apply_X_ptr_handle_cref , return_value_policy()) - .def("apply_X_ref_pyobject", apply_X_ref_pyobject + .def("apply_X_ref_handle", apply_X_ref_handle , return_value_policy()) .def("apply_cstring_cstring", apply_cstring_cstring) diff --git a/test/callbacks.py b/test/callbacks.py index 9a48ec2c..937961fd 100644 --- a/test/callbacks.py +++ b/test/callbacks.py @@ -74,27 +74,27 @@ succeed: >>> last_x.value() 43 ->>> y = apply_X_ref_pyobject(identity, x) +>>> y = apply_X_ref_handle(identity, x) >>> assert y.value() == x.value() >>> increment(x) >>> assert y.value() == x.value() ->>> y = apply_X_ptr_pyobject(identity, x) +>>> y = apply_X_ptr_handle_cref(identity, x) >>> assert y.value() == x.value() >>> increment(x) >>> assert y.value() == x.value() ->>> y = apply_X_ptr_pyobject(identity, None) +>>> y = apply_X_ptr_handle_cref(identity, None) >>> y >>> def new_x(ignored): ... return X(666) ... ->>> try: apply_X_ref_pyobject(new_x, 1) +>>> try: apply_X_ref_handle(new_x, 1) ... except ReferenceError: pass ... else: print 'no error' ->>> try: apply_X_ptr_pyobject(new_x, 1) +>>> try: apply_X_ptr_handle_cref(new_x, 1) ... except ReferenceError: pass ... else: print 'no error' @@ -113,6 +113,10 @@ succeed: >>> apply_char_char(identity, 'x') 'x' + +>>> assert apply_to_own_type(identity) is type(identity) + +>>> assert apply_object_object(identity, identity) is identity ''' def run(args = None): diff --git a/test/object.cpp b/test/object.cpp new file mode 100755 index 00000000..f3a31011 --- /dev/null +++ b/test/object.cpp @@ -0,0 +1,149 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#include +#include + +using namespace boost::python; + +object call_object_3(object f) +{ + return f(3); +} + +object message() +{ + return object("hello, world!"); +} + +object number() +{ + return object(42); +} + +object obj_getattr(object x, char const* name) +{ + return x._(name); +} + +object obj_const_getattr(object const& x, char const* name) +{ + return x._(name); +} + +void obj_setattr(object x, char const* name, object value) +{ + x._(name) = value; +} + +void obj_setattr42(object x, char const* name) +{ + x._(name) = 42; +} + +void obj_moveattr(object& x, char const* src, char const* dst) +{ + x._(dst) = x._(src); +} + +object obj_getitem(object x, object key) +{ + return x[key]; +} + +object obj_getitem3(object x) +{ + return x[3]; +} + +object obj_const_getitem(object const& x, object key) +{ + return x[key]; +} + +void obj_setitem(object x, object key, object value) +{ + x[key] = value; +} + +void obj_setitem42(object x, object key) +{ + x[key] = 42; +} + +void obj_moveitem(object& x, object src, object dst) +{ + x[dst] = x[src]; +} + +void obj_moveitem2(object const& x_src, object k_src, object& x_dst, object k_dst) +{ + x_dst[k_dst] = x_src[k_src]; +} + +bool test(object y) +{ + return y; +} + +bool test_not(object y) +{ + return !y; +} + +bool test_attr(object y, char* name) +{ + return y._(name); +} + +bool test_not_attr(object y, char* name) +{ + return !y._(name); +} + +bool test_item(object y, object key) +{ + return y[key]; +} + +bool test_not_item(object y, object key) +{ + return !y[key]; +} + +BOOST_PYTHON_MODULE_INIT(object_ext) +{ + module("object_ext") + .def("call_object_3", call_object_3) + .def("message", message) + .def("number", number) + + .def("obj_getattr", obj_getattr) + .def("obj_const_getattr", obj_const_getattr) + .def("obj_setattr", obj_setattr) + .def("obj_setattr42", obj_setattr42) + .def("obj_moveattr", obj_moveattr) + + + .def("obj_getitem", obj_getitem) + .def("obj_getitem3", obj_getitem) + .def("obj_const_getitem", obj_const_getitem) + .def("obj_setitem", obj_setitem) + .def("obj_setitem42", obj_setitem42) + .def("obj_moveitem", obj_moveitem) + .def("obj_moveitem2", obj_moveitem2) + + .def("test", test) + .def("test_not", test_not) + + .def("test_attr", test_attr) + .def("test_not_attr", test_not_attr) + + .def("test_item", test_item) + .def("test_not_item", test_not_item) + ; +} + +#include "module_tail.cpp" diff --git a/test/object.py b/test/object.py new file mode 100644 index 00000000..68e46fe3 --- /dev/null +++ b/test/object.py @@ -0,0 +1,95 @@ +''' +>>> from object_ext import * +>>> def print1(x): +... print x +>>> call_object_3(print1) +3 +>>> message() +'hello, world!' +>>> number() +42 + +>>> test('hi') +1 +>>> test(None) +0 +>>> test_not('hi') +0 +>>> test_not(0) +1 + + Attributes + +>>> class X: pass +... +>>> x = X() + +>>> try: obj_getattr(x, 'foo') +... except AttributeError: pass +... else: print 'expected an exception' + +>>> obj_setattr(x, 'foo', 1) +>>> x.foo +1 +>>> obj_getattr(x, 'foo') +1 +>>> obj_const_getattr(x, 'foo') +1 +>>> obj_setattr42(x, 'foo') +>>> x.foo +42 +>>> obj_moveattr(x, 'foo', 'bar') +>>> x.bar +42 +>>> test_attr(x, 'foo') +1 +>>> test_not_attr(x, 'foo') +0 +>>> x.foo = None +>>> test_attr(x, 'foo') +0 +>>> test_not_attr(x, 'foo') +1 + + Items + +>>> d = {} +>>> obj_setitem(d, 'foo', 1) +>>> d['foo'] +1 +>>> obj_getitem(d, 'foo') +1 +>>> obj_const_getitem(d, 'foo') +1 +>>> obj_setitem42(d, 'foo') +>>> d['foo'] +42 +>>> obj_moveitem(d, 'foo', 'bar') +>>> d['bar'] +42 +>>> obj_moveitem2(d, 'bar', d, 'baz') +>>> d['baz'] +42 +>>> test_item(d, 'foo') +1 +>>> test_not_item(d, 'foo') +0 +>>> d['foo'] = None +>>> test_item(d, 'foo') +0 +>>> test_not_item(d, 'foo') +1 +''' + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + sys.exit(run()[0]) diff --git a/test/object_fail1.cpp b/test/object_fail1.cpp new file mode 100755 index 00000000..3b09e71d --- /dev/null +++ b/test/object_fail1.cpp @@ -0,0 +1,12 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#include + +int f(boost::python::object const& x) +{ + x._("hello") = 1; + return 0; +} diff --git a/test/object_manager.cpp b/test/object_manager.cpp new file mode 100755 index 00000000..75c816bc --- /dev/null +++ b/test/object_manager.cpp @@ -0,0 +1,37 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#include +#include +#include +#include "test_class.hpp" + +using namespace boost::python; +using namespace boost::python::converter; + +template struct undefined; + +int main() +{ + BOOST_STATIC_ASSERT(is_object_manager >::value); + BOOST_STATIC_ASSERT(!is_object_manager::value); + BOOST_STATIC_ASSERT(!is_object_manager >::value); + + BOOST_STATIC_ASSERT(is_reference_to_object_manager&>::value); + BOOST_STATIC_ASSERT(is_reference_to_object_manager const&>::value); + BOOST_STATIC_ASSERT(is_reference_to_object_manager volatile&>::value); + BOOST_STATIC_ASSERT(is_reference_to_object_manager const volatile&>::value); + +// undefined >::t1> x1; +// undefined >::t2> x2; + + BOOST_STATIC_ASSERT(!is_reference_to_object_manager >::value); + BOOST_STATIC_ASSERT(!is_reference_to_object_manager >::value); + BOOST_STATIC_ASSERT(!is_reference_to_object_manager&>::value); + BOOST_STATIC_ASSERT(!is_reference_to_object_managerconst&>::value); + + return 0; +} + diff --git a/test/raw_pyobject_fail1.cpp b/test/raw_pyobject_fail1.cpp new file mode 100755 index 00000000..8fe73d68 --- /dev/null +++ b/test/raw_pyobject_fail1.cpp @@ -0,0 +1,12 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#include + +int main() +{ + boost::python::converter::arg_to_python x(0); + return 0; +} diff --git a/test/raw_pyobject_fail2.cpp b/test/raw_pyobject_fail2.cpp new file mode 100755 index 00000000..7a0e79d9 --- /dev/null +++ b/test/raw_pyobject_fail2.cpp @@ -0,0 +1,14 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#include + +struct X : PyObject {}; + +int main() +{ + boost::python::converter::arg_to_python x(0); + return 0; +} diff --git a/test/test_builtin_converters.cpp b/test/test_builtin_converters.cpp index 25ad7fee..bf7d991e 100644 --- a/test/test_builtin_converters.cpp +++ b/test/test_builtin_converters.cpp @@ -6,6 +6,9 @@ #include #include #include +#include +#include +#include template struct by_value @@ -25,11 +28,37 @@ struct by_const_reference } }; +template +struct by_reference +{ + static T rewrap(T& x) + { + return x; + } +}; + +using boost::python::handle; +using boost::python::object; +using boost::python::borrowed; + +// Used to test that arbitrary handle<>s can be returned +handle get_type(handle<> x) +{ + return handle(borrowed(x->ob_type)); +} + +handle<> return_null_handle() +{ + return handle<>(); +} + char const* rewrap_value_mutable_cstring(char* x) { return x; } BOOST_PYTHON_MODULE_INIT(builtin_converters) { boost::python::module("builtin_converters") + .def("get_type", get_type) + .def("return_null_handle", return_null_handle) .def("rewrap_value_bool", by_value::rewrap) .def("rewrap_value_char", by_value::rewrap) @@ -53,6 +82,8 @@ BOOST_PYTHON_MODULE_INIT(builtin_converters) .def("rewrap_value_complex_long_double", by_value >::rewrap) .def("rewrap_value_string", by_value::rewrap) .def("rewrap_value_cstring", by_value::rewrap) + .def("rewrap_value_handle", by_value >::rewrap) + .def("rewrap_value_object", by_value::rewrap) // Expose this to illustrate our failings ;-). See test_builtin_converters.py .def("rewrap_value_mutable_cstring", rewrap_value_mutable_cstring) @@ -80,6 +111,11 @@ BOOST_PYTHON_MODULE_INIT(builtin_converters) .def("rewrap_const_reference_complex_long_double", by_const_reference >::rewrap) .def("rewrap_const_reference_string", by_const_reference::rewrap) .def("rewrap_const_reference_cstring", by_const_reference::rewrap) + .def("rewrap_const_reference_handle", by_const_reference >::rewrap) + .def("rewrap_const_reference_object", by_const_reference::rewrap) + + + .def("rewrap_reference_object", by_reference::rewrap) ; } diff --git a/test/test_builtin_converters.py b/test/test_builtin_converters.py index 6600c6b7..fb4725ba 100644 --- a/test/test_builtin_converters.py +++ b/test/test_builtin_converters.py @@ -73,6 +73,12 @@ >>> rewrap_value_string('yo, wassup?') 'yo, wassup?' +>>> rewrap_value_handle(1) +1 +>>> x = 'hi' +>>> assert rewrap_value_handle(x) is x +>>> assert rewrap_value_object(x) is x + Note that we can currently get a mutable pointer into an immutable Python string: @@ -134,6 +140,13 @@ >>> rewrap_const_reference_string('yo, wassup?') 'yo, wassup?' +>>> rewrap_const_reference_handle(1) +1 +>>> x = 'hi' +>>> assert rewrap_const_reference_handle(x) is x +>>> assert rewrap_const_reference_object(x) is x +>>> assert rewrap_reference_object(x) is x + Check that None <==> NULL @@ -180,6 +193,13 @@ Check that classic classes also work >>> abs(rewrap_value_complex_double(FortyTwo()) - (4+.2j)) < .000001 1 +# show that arbitrary handle instantiations can be returned +>>> get_type(1) is type(1) +1 + +>>> try: return_null_handle() +... except: pass +... else: print 'expectd an exception' """ def run(args = None):