diff --git a/include/boost/python/back_reference.hpp b/include/boost/python/back_reference.hpp index 5e9f02ba..29ad6163 100644 --- a/include/boost/python/back_reference.hpp +++ b/include/boost/python/back_reference.hpp @@ -7,21 +7,24 @@ # define BACK_REFERENCE_DWA2002510_HPP # include -# include +# include +# include namespace boost { namespace python { template struct back_reference { + private: // types + typedef typename detail::dependent::type source_t; public: typedef T type; back_reference(PyObject*, T); - object const& source() const; + source_t const& source() const; T get() const; private: - object m_source; + source_t m_source; T m_value; }; @@ -82,7 +85,7 @@ back_reference::back_reference(PyObject* p, T x) } template -object const& back_reference::source() const +typename back_reference::source_t const& back_reference::source() const { return m_source; } diff --git a/include/boost/python/cast.hpp b/include/boost/python/cast.hpp index 1897fc60..d20cbd3a 100755 --- a/include/boost/python/cast.hpp +++ b/include/boost/python/cast.hpp @@ -8,6 +8,7 @@ # include # include +# include # include # include # include @@ -16,19 +17,42 @@ namespace boost { namespace python { namespace detail { - template - inline Target* upcast(Target* p, yes_convertible) + template inline Target* upcast_impl(Source*, Target*); + + template + inline Target* upcast(Source* p, yes_convertible, no_convertible, Target*) { return p; } - template - inline Target* upcast(Source* p, no_convertible, boost::type* = 0) + template + inline Target* upcast(Source* p, no_convertible, no_convertible, Target*) { typedef typename base_type_traits::type base; - return detail::upcast((base*)p, convertible::check((base*)0)); + + return detail::upcast_impl((base*)p, (Target*)0); } + template + struct upcaster + { + template + static inline T* execute(T* x, T*) { return x; } + }; + + template <> + struct upcaster + { + template + static inline Target* execute(Source* x, Target*) + { + return detail::upcast( + x, detail::convertible::check(x) + , detail::convertible::check((Target*)0) + , (Target*)0); + } + }; + template inline Target* downcast(Source* p, yes_convertible) @@ -48,6 +72,16 @@ namespace detail { typedef char must_be_a_complete_type[sizeof(T)]; } + + template + inline Target* upcast_impl(Source* x, Target*) + { + typedef typename add_cv::type src_t; + typedef typename add_cv::type target_t; + static bool const same = is_same::value; + + return detail::upcaster::execute(x, (Target*)0); + } } template @@ -55,7 +89,8 @@ inline Target* upcast(Source* x, Target* = 0) { detail::assert_castable(); detail::assert_castable(); - return detail::upcast(x, detail::convertible::check(x)); + return detail::upcast_impl(x, (Target*)0); + } template diff --git a/include/boost/python/class.hpp b/include/boost/python/class.hpp index e03f1838..799fd498 100644 --- a/include/boost/python/class.hpp +++ b/include/boost/python/class.hpp @@ -12,7 +12,6 @@ # include # include # include -# include # include # include # include @@ -26,6 +25,8 @@ # include # include # include +# include +# include namespace boost { namespace python { @@ -101,30 +102,19 @@ class class_ : public objects::class_base template self& def(char const* name, F f) { - // Use function::add_to_namespace to achieve overloading if - // appropriate. - objects::function::add_to_namespace( - *this, name - , object( - detail::new_reference( - detail::wrap_function( - // This bit of nastiness casts F to a member function of T if possible. - detail::member_function_cast::stage1(f).stage2((T*)0).stage3(f) - )))); + this->def_impl(name, f, 0, &f); return *this; } template self& def(char const* name, Fn fn, CallPolicy policy) { - this->def(name + return this->def(name , boost::python::make_function( // This bit of nastiness casts F to a member function of T if possible. detail::member_function_cast::stage1(fn).stage2((T*)0).stage3(fn) , policy) ); - - return *this; } template @@ -133,12 +123,7 @@ class class_ : public objects::class_base typedef detail::operator_ op_t; // Use function::add_to_namespace to achieve overloading if // appropriate. - objects::function::add_to_namespace( - *this, op.name() - , object( - detail::new_reference( - detail::wrap_function(&op_t::template apply::execute)))); - return *this; + return this->def(op.name(), &op_t::template apply::execute); } // Define the constructor with the given Args, which should be an @@ -146,26 +131,24 @@ class class_ : public objects::class_base template self& def_init(Args const&) { - def("__init__", - make_constructor( + return this->def("__init__", + python::make_constructor( // Using runtime type selection works around a CWPro7 bug. objects::select_holder((held_type*)0).get() ) ); - return *this; } template self& def_init(Args const&, CallPolicy policy) { - def("__init__", - make_constructor( + return this->def("__init__", + python::make_constructor( policy // Using runtime type selection works around a CWPro7 bug. , objects::select_holder((held_type*)0).get() ) ); - return *this; } // Define the default constructor. @@ -216,6 +199,24 @@ class class_ : public objects::class_base return *this; } + private: // helper functions + + template + inline void def_impl(char const* name, F const& f, char const* doc, ...) + { + objects::add_to_namespace( + *this, name, make_function( + // This bit of nastiness casts F to a member function of T if possible. + detail::member_function_cast::stage1(f).stage2((T*)0).stage3(f)) + , doc); + } + + template + inline void def_impl(char const* name, F const& f, char const* doc, object const volatile*) + { + objects::add_to_namespace(*this, name, f, doc); + } + private: // types typedef objects::class_id class_id; diff --git a/include/boost/python/converter/arg_to_python.hpp b/include/boost/python/converter/arg_to_python.hpp index eb1cd80c..c936b81d 100755 --- a/include/boost/python/converter/arg_to_python.hpp +++ b/include/boost/python/converter/arg_to_python.hpp @@ -13,12 +13,16 @@ # include # include # include +# include +# include +# include # include # include # include // Bring in specializations # include # include +# include namespace boost { namespace python { namespace converter { @@ -26,6 +30,12 @@ namespace detail { BOOST_PYTHON_DECL void throw_no_class_registered(); + template + struct function_arg_to_python : handle<> + { + function_arg_to_python(T const& x); + }; + template struct reference_arg_to_python : handle<> { @@ -80,6 +90,9 @@ namespace detail BOOST_STATIC_CONSTANT( bool, is_string = python::detail::is_string_literal::value); + BOOST_STATIC_CONSTANT( + bool, function = is_function::value | python::detail::is_pointer_to_function::value | is_member_function_pointer::value); + BOOST_STATIC_CONSTANT( bool, manager = is_object_manager::value); @@ -99,18 +112,22 @@ namespace detail is_string , arg_to_python , typename mpl::select_type< - manager - , object_manager_arg_to_python + function + , function_arg_to_python , 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 @@ -168,6 +185,12 @@ namespace detail } // --------- + template + inline function_arg_to_python::function_arg_to_python(T const& x) + : handle<>(python::objects::make_function_handle(x)) + { + } + template inline value_arg_to_python::value_arg_to_python(T const& x) : arg_to_python_base(&x, registered::converters) diff --git a/include/boost/python/data_members.hpp b/include/boost/python/data_members.hpp index f186c1d0..01190811 100644 --- a/include/boost/python/data_members.hpp +++ b/include/boost/python/data_members.hpp @@ -8,12 +8,13 @@ # include # include -# include # include # include # include # include # include +# include +# include namespace boost { namespace python { diff --git a/include/boost/python/detail/dependent.hpp b/include/boost/python/detail/dependent.hpp new file mode 100644 index 00000000..4fc48766 --- /dev/null +++ b/include/boost/python/detail/dependent.hpp @@ -0,0 +1,28 @@ +// 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 DEPENDENT_DWA200286_HPP +# define DEPENDENT_DWA200286_HPP + +namespace boost { namespace python { namespace detail { + +// A way to turn a concrete type T into a type dependent on U. This +// keeps conforming compilers (those implementing proper 2-phase +// name lookup for templates) from complaining about incomplete +// types in situations where it would otherwise be inconvenient or +// impossible to re-order code so that all types are defined in time. + +// One such use is when we must return an incomplete T from a member +// function template (which must be defined in the class body to +// keep MSVC happy). +template +struct dependent +{ + typedef T type; +}; + +}}} // namespace boost::python::detail + +#endif // DEPENDENT_DWA200286_HPP diff --git a/include/boost/python/detail/module_base.hpp b/include/boost/python/detail/module_base.hpp index aaa6a135..4ef00cfd 100644 --- a/include/boost/python/detail/module_base.hpp +++ b/include/boost/python/detail/module_base.hpp @@ -7,6 +7,7 @@ # define MODULE_BASE_DWA2002227_HPP # include # include +# include namespace boost { namespace python { namespace detail { @@ -18,14 +19,13 @@ class BOOST_PYTHON_DECL module_base ~module_base(); // Add elements to the module - void setattr(const char* name, PyObject*); - void setattr(const char* name, handle<> const&); void add(type_handle const&); // just use the type's name // Return a reference to the Python module object being built inline handle<> object() const; protected: + void setattr_doc(const char* name, python::object const&, char const* doc); void add_class(type_handle const& class_obj); private: diff --git a/include/boost/python/detail/wrap_function.hpp b/include/boost/python/detail/wrap_function.hpp deleted file mode 100644 index dcc3daca..00000000 --- a/include/boost/python/detail/wrap_function.hpp +++ /dev/null @@ -1,52 +0,0 @@ -// 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 WRAP_FUNCTION_DWA2002118_HPP -# define WRAP_FUNCTION_DWA2002118_HPP - -# include -# include -# include -# include -# include -# include -# include -# include - -namespace boost { namespace python { - -template class reference; - -namespace detail { - -// A function which converts its argument into a Python callable -// object. Not very general yet! - -// This should eventually be replaced with a mechanism for specialized -// wrap/unwrap objects. In other words, to_python(f), where f is a -// function pointer or function type, should produce a callable Python -// object. - -template -inline PyObject* wrap_function_aux(F const& f, PyObject*) { return f; } - -template -inline PyObject* wrap_function_aux(F const&, boost::python::handle x) { return x.release(); } - -template -inline PyObject* wrap_function_aux(F const&, object const& x) { return python::incref(x.ptr()); } - -template -inline PyObject* wrap_function_aux(F const& f, ...) { return make_function(f); } - -template -PyObject* wrap_function(F f) -{ - return wrap_function_aux(f, f); -} - -}}} // namespace boost::python::detail - -#endif // WRAP_FUNCTION_DWA2002118_HPP diff --git a/include/boost/python/make_function.hpp b/include/boost/python/make_function.hpp index 7b2ba79d..decdf5b4 100644 --- a/include/boost/python/make_function.hpp +++ b/include/boost/python/make_function.hpp @@ -6,7 +6,7 @@ #ifndef MAKE_FUNCTION_DWA20011221_HPP # define MAKE_FUNCTION_DWA20011221_HPP -# include +# include # include # include # include @@ -17,48 +17,45 @@ namespace boost { namespace python { template -objects::function* make_function(F f) +object make_function(F f) { - return new objects::function( - objects::py_function( - ::boost::bind(detail::caller(), f, _1, _2, default_call_policies())) + return objects::function_object( + ::boost::bind(detail::caller(), f, _1, _2, default_call_policies()) , detail::arg_tuple_size::value); } template -objects::function* make_function(F f, Policies const& policies) +object make_function(F f, Policies const& policies) { - return new objects::function( - objects::py_function( - ::boost::bind(detail::caller(), f, _1, _2, policies)) + return objects::function_object( + ::boost::bind(detail::caller(), f, _1, _2, policies) , detail::arg_tuple_size::value); } template -objects::function* make_constructor(HolderGenerator* = 0, ArgList* = 0) +object make_constructor(HolderGenerator* = 0, ArgList* = 0) { enum { nargs = mpl::size::value }; - return new objects::function( - objects::py_function( - ::boost::bind(detail::caller(), - objects::make_holder - ::template apply::execute - , _1, _2, default_call_policies())) + return objects::function_object( + ::boost::bind( + detail::caller() + , objects::make_holder + ::template apply::execute + , _1, _2, default_call_policies()) , nargs + 1); } template -objects::function* make_constructor(Policies const& policies, HolderGenerator* = 0, ArgList* = 0) +object make_constructor(Policies const& policies, HolderGenerator* = 0, ArgList* = 0) { enum { nargs = mpl::size::value }; - return new objects::function( - objects::py_function( + return objects::function_object( ::boost::bind(detail::caller(), objects::make_holder ::template apply::execute - , _1, _2, policies)) + , _1, _2, policies) , nargs + 1); } diff --git a/include/boost/python/module.hpp b/include/boost/python/module.hpp index 25f8cf05..a4d7a4db 100644 --- a/include/boost/python/module.hpp +++ b/include/boost/python/module.hpp @@ -12,6 +12,7 @@ # include # include # include +# include namespace boost { namespace python { @@ -24,10 +25,14 @@ class module : public detail::module_base : base(name) {} // Add elements to the module - module& setattr(const char* name, PyObject*); - module& setattr(const char* name, PyTypeObject*); - module& setattr(const char* name, handle<> const&); - module& add(PyTypeObject* x); // just use the type's name + template + module& setattr(const char* name, T const& x) + { + this->module_base::setattr_doc(name, python::object(x), 0); + return *this; + } + + module& add(type_handle x); // just use the type's name template module& add(class_ const& c) @@ -37,17 +42,17 @@ class module : public detail::module_base } template - module& def(char const* name, Fn fn) + module& def(char const* name, Fn fn, char const* doc = 0) { - this->setattr(name, boost::python::make_function(fn)); + this->setattr_doc(name, boost::python::make_function(fn), doc); return *this; } template - module& def(char const* name, Fn fn, ResultHandler handler) + module& def(char const* name, Fn fn, ResultHandler handler, char const* doc = 0) { - this->setattr(name, boost::python::make_function(fn, handler)); + this->setattr_doc(name, boost::python::make_function(fn, handler), doc); return *this; } }; @@ -55,27 +60,9 @@ class module : public detail::module_base // // inline implementations // -inline module& module::setattr(const char* name, PyObject* x) +inline module& module::add(type_handle x) { - this->base::setattr(name, x); - return *this; -} - -inline module& module::setattr(const char* name, PyTypeObject* x) -{ - this->base::setattr(name, (PyObject*)x); - return *this; -} - -inline module& module::setattr(const char* name, handle<> const& x) -{ - this->base::setattr(name, x); - return *this; -} - -inline module& module::add(PyTypeObject* x) -{ - this->base::add(handle<>(borrowed(x))); + this->base::add(x); return *this; } diff --git a/include/boost/python/object/add_to_namespace.hpp b/include/boost/python/object/add_to_namespace.hpp new file mode 100644 index 00000000..6a862b3d --- /dev/null +++ b/include/boost/python/object/add_to_namespace.hpp @@ -0,0 +1,24 @@ +// 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 ADD_TO_NAMESPACE_DWA200286_HPP +# define ADD_TO_NAMESPACE_DWA200286_HPP + +# include + +namespace boost { namespace python { namespace objects { + +// +// A setattr that's "smart" about function overloading (and docstrings). +// +BOOST_PYTHON_DECL void add_to_namespace( + object const& name_space, char const* name, object const& attribute); + +BOOST_PYTHON_DECL void add_to_namespace( + object const& name_space, char const* name, object const& attribute, char const* doc); + +}}} // namespace boost::python::objects + +#endif // ADD_TO_NAMESPACE_DWA200286_HPP diff --git a/include/boost/python/object/function.hpp b/include/boost/python/object/function.hpp index 80a50dd0..1e5fdfe8 100644 --- a/include/boost/python/object/function.hpp +++ b/include/boost/python/object/function.hpp @@ -10,37 +10,55 @@ # include # include # include -# include +# include +# include namespace boost { namespace python { namespace objects { -// We use boost::function to avoid generating lots of virtual tables -typedef boost::function2 py_function; - struct BOOST_PYTHON_DECL function : PyObject { - function(py_function, unsigned min_args, unsigned max_args = 0); + function(py_function const&, unsigned min_args, unsigned max_args = 0); ~function(); PyObject* call(PyObject*, PyObject*) const; - // Add an attributeto the name_space with the given name. If it is + // Add an attribute to the name_space with the given name. If it is // a function object (this class), and an existing function is // already there, add it as an overload. static void add_to_namespace( object const& name_space, char const* name, object const& attribute); + + static void add_to_namespace( + object const& name_space, char const* name, object const& attribute, char const* doc); + + object const& doc() const; + void doc(object const& x); private: // helper functions void argument_error(PyObject* args, PyObject* keywords) const; - void add_overload(function*); + void add_overload(handle const&); private: // data members py_function m_fn; unsigned m_min_args; unsigned m_max_args; - function* m_overloads; + handle m_overloads; + object m_doc; }; +// +// implementations +// +inline object const& function::doc() const +{ + return this->m_doc; +} + +inline void function::doc(object const& x) +{ + this->m_doc = x; +} + }}} // namespace boost::python::objects #endif // FUNCTION_DWA20011214_HPP diff --git a/include/boost/python/object/function_handle.hpp b/include/boost/python/object/function_handle.hpp new file mode 100644 index 00000000..f29c2e35 --- /dev/null +++ b/include/boost/python/object/function_handle.hpp @@ -0,0 +1,40 @@ +// 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 FUNCTION_HANDLE_DWA2002725_HPP +# define FUNCTION_HANDLE_DWA2002725_HPP +# include +# include +# include +# include +# include +# include + +namespace boost { namespace python { namespace objects { + +BOOST_PYTHON_DECL handle<> function_handle_impl(py_function const& f, unsigned min_args, unsigned max_args = 0); + +// Just like function_object, but returns a handle<> instead. Using +// this for arg_to_python<> allows us to break a circular dependency +// between object and arg_to_python. +template +inline handle<> function_handle(F const& f, unsigned min_args, unsigned max_args = 0) +{ + return objects::function_handle_impl(objects::py_function(f), min_args, max_args); +} + +// Just like make_function, but returns a handle<> intead. Same +// reasoning as above. +template +handle<> make_function_handle(F f) +{ + return objects::function_handle( + ::boost::bind(python::detail::caller(), f, _1, _2, default_call_policies()) + , python::detail::arg_tuple_size::value); +} + +}}} // namespace boost::python::objects + +#endif // FUNCTION_HANDLE_DWA2002725_HPP diff --git a/include/boost/python/object/function_object.hpp b/include/boost/python/object/function_object.hpp index b638ac01..03535ec3 100644 --- a/include/boost/python/object/function_object.hpp +++ b/include/boost/python/object/function_object.hpp @@ -5,19 +5,20 @@ // to its suitability for any purpose. #ifndef FUNCTION_OBJECT_DWA2002725_HPP # define FUNCTION_OBJECT_DWA2002725_HPP -# include +# include +# include # include namespace boost { namespace python { namespace objects { +BOOST_PYTHON_DECL api::object function_object_impl(boost::function2 const& f, unsigned min_args, unsigned max_args = 0); + template inline object function_object(F const& f, unsigned min_args, unsigned max_args = 0) { - return python::object( - python::detail::new_non_null_reference( - new function(objects::py_function(f), min_args, max_args))); + return objects::function_object_impl(boost::function2(f), min_args, max_args); } -}}} // namespace boost::python::object +}}} // namespace boost::python::objects #endif // FUNCTION_OBJECT_DWA2002725_HPP diff --git a/include/boost/python/object/iterator.hpp b/include/boost/python/object/iterator.hpp index c39131c6..13862e6f 100644 --- a/include/boost/python/object/iterator.hpp +++ b/include/boost/python/object/iterator.hpp @@ -10,7 +10,7 @@ # include # include # include -# include +# include # include # include # include @@ -126,11 +126,10 @@ namespace detail return object(class_obj); // Make a callable object which can be used as the iterator's next() function. - handle<> next_function( - new objects::function( - objects::py_function( - bind(&detail::iterator_next::execute, _1, _2, policies)) - , 1)); + object next_function = + objects::function_object( + bind(&detail::iterator_next::execute, _1, _2, policies) + , 1); return class_(name) .def("__iter__", identity_function()) @@ -192,17 +191,14 @@ inline object make_iterator_function( { typedef typename Accessor1::result_type result_type; - return object( - python::detail::new_non_null_reference( - new objects::function( - objects::py_function( - boost::bind( - &detail::make_iterator_help< - Target,result_type,Accessor1,Accessor2,NextPolicies - >::create - , get_start, get_finish, _1, _2)) - ,1 )) - ); + return + objects::function_object( + boost::bind( + &detail::make_iterator_help< + Target,result_type,Accessor1,Accessor2,NextPolicies + >::create + , get_start, get_finish, _1, _2) + , 1 ); } // diff --git a/include/boost/python/object/iterator_core.hpp b/include/boost/python/object/iterator_core.hpp index c3d5f6ae..655fc71e 100644 --- a/include/boost/python/object/iterator_core.hpp +++ b/include/boost/python/object/iterator_core.hpp @@ -6,11 +6,12 @@ #ifndef ITERATOR_CORE_DWA2002512_HPP # define ITERATOR_CORE_DWA2002512_HPP -# include +# include +# include namespace boost { namespace python { namespace objects { -BOOST_PYTHON_DECL handle<> identity_function(); +BOOST_PYTHON_DECL object const& identity_function(); BOOST_PYTHON_DECL void set_stop_iteration_error(); }}} // namespace boost::python::object diff --git a/include/boost/python/object/pickle_support.hpp b/include/boost/python/object/pickle_support.hpp index 44e2103e..10a5f4f8 100644 --- a/include/boost/python/object/pickle_support.hpp +++ b/include/boost/python/object/pickle_support.hpp @@ -8,10 +8,11 @@ #include #include +#include namespace boost { namespace python { -handle<> make_instance_reduce_function(); +BOOST_PYTHON_DECL object const& make_instance_reduce_function(); struct pickle_suite; diff --git a/include/boost/python/object/py_function.hpp b/include/boost/python/object/py_function.hpp new file mode 100644 index 00000000..0682d692 --- /dev/null +++ b/include/boost/python/object/py_function.hpp @@ -0,0 +1,22 @@ +// 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 PY_FUNCTION_DWA200286_HPP +# define PY_FUNCTION_DWA200286_HPP +# include + +namespace boost { namespace python { namespace objects { + +// This type is used as a "generalized Python callback", wrapping the +// function signature: +// +// PyObject* (PyObject* args, PyObject* keywords) +// +// We use boost::function to avoid generating lots of virtual tables +typedef boost::function2 py_function; + +}}} // namespace boost::python::objects + +#endif // PY_FUNCTION_DWA200286_HPP diff --git a/include/boost/python/object_call.hpp b/include/boost/python/object_call.hpp index 22e88847..31b2eff9 100644 --- a/include/boost/python/object_call.hpp +++ b/include/boost/python/object_call.hpp @@ -11,10 +11,10 @@ #define N BOOST_PP_ITERATION() template - typename dependent::type + typename detail::dependent::type operator()(BOOST_PYTHON_BINARY_ENUM(N, A, const& a)) const { - typedef typename dependent::type obj; + typedef typename detail::dependent::type obj; U const& self = *static_cast(this); return call(get_managed_object(self, tag), BOOST_PYTHON_UNARY_ENUM(N, a)); } diff --git a/include/boost/python/object_core.hpp b/include/boost/python/object_core.hpp index 496752dc..22bd2750 100755 --- a/include/boost/python/object_core.hpp +++ b/include/boost/python/object_core.hpp @@ -16,6 +16,7 @@ # include # include # include +# include # include @@ -76,16 +77,6 @@ namespace api template struct object_initializer; - // A way to turn a conrete type T into a type dependent on U. This - // keeps conforming compilers from complaining about returning an - // incomplete T from a template member function (which must be - // defined in the class body to keep MSVC happy). - template - struct dependent - { - typedef T type; - }; - class object; typedef PyObject* (object::*bool_type)() const; diff --git a/src/module.cpp b/src/module.cpp index b07cfe35..4563db31 100644 --- a/src/module.cpp +++ b/src/module.cpp @@ -28,21 +28,16 @@ module_base::~module_base() { } -void module_base::setattr(const char* name, PyObject* x) -{ - setattr(name, handle<>(x)); -} - -void module_base::setattr(char const* name, handle<> const& x) +void module_base::setattr_doc(const char* name, python::object const& x, char const* doc) { // Use function::add_to_namespace to achieve overloading if // appropriate. - objects::function::add_to_namespace(python::object(m_module), name, python::object(x)); + objects::function::add_to_namespace(python::object(m_module), name, x, doc); } void module_base::add(type_handle const& x) { - this->setattr(x->tp_name, x); + this->setattr_doc(x->tp_name, python::object(x), 0); } void module_base::add_class(type_handle const& class_obj) diff --git a/src/object/function.cpp b/src/object/function.cpp index 53cad982..a09717fc 100644 --- a/src/object/function.cpp +++ b/src/object/function.cpp @@ -4,22 +4,24 @@ // "as is" without express or implied warranty, and with no claim as // to its suitability for any purpose. +#include #include +#include #include #include #include #include #include +#include namespace boost { namespace python { namespace objects { extern PyTypeObject function_type; -function::function(py_function implementation, unsigned min_args, unsigned max_args) +function::function(py_function const& implementation, unsigned min_args, unsigned max_args) : m_fn(implementation) , m_min_args(min_args) - , m_max_args(std::max(max_args,min_args)) - , m_overloads(0) + , m_max_args(std::max(max_args,min_args)) { PyObject* p = this; PyObject_INIT(p, &function_type); @@ -27,8 +29,6 @@ function::function(py_function implementation, unsigned min_args, unsigned max_a function::~function() { - PyObject* overloads = m_overloads; - Py_XDECREF(overloads); } PyObject* function::call(PyObject* args, PyObject* keywords) const @@ -52,7 +52,7 @@ PyObject* function::call(PyObject* args, PyObject* keywords) const if (result != 0 || PyErr_Occurred()) return result; } - f = f->m_overloads; + f = f->m_overloads.get(); } while (f); // None of the overloads matched; time to generate the error message @@ -66,17 +66,18 @@ void function::argument_error(PyObject* args, PyObject* keywords) const PyErr_BadArgument(); } -void function::add_overload(function* overload_) +void function::add_overload(handle const& overload_) { - Py_XINCREF(overload_); - function* parent = this; - while (parent->m_overloads != 0) - { - parent = parent->m_overloads; - } + while (parent->m_overloads) + parent = parent->m_overloads.get(); + parent->m_overloads = overload_; + + // If we have no documentation, get the docs from the overload + if (!m_doc) + m_doc = overload_->m_doc; } namespace @@ -146,10 +147,10 @@ namespace return Py_NotImplemented; } - function* not_implemented_function() + handle not_implemented_function() { static object keeper(function_object(¬_implemented_impl, 2, 3)); - return (function*)keeper.ptr(); + return handle(borrowed(downcast(keeper.ptr()))); } } @@ -172,16 +173,17 @@ void function::add_to_namespace( if (dict == 0) throw_error_already_set(); - - handle<> existing( allow_null(::PyObject_GetItem(dict, name.ptr())) ); + + // This isn't quite typesafe. We'll shoot first by assuming + // the thing is a function*, then ask questions later. The code works nicer that way. + handle existing( + allow_null(downcast(::PyObject_GetItem(dict, name.ptr()))) + ); if (existing.get()) { if (existing->ob_type == &function_type) - { - static_cast(attribute.ptr())->add_overload( - static_cast(existing.get())); - } + static_cast(attribute.ptr())->add_overload(existing); } // Binary operators need an additional overload which returns NotImplemented else if (is_binary_operator(name_)) @@ -190,13 +192,24 @@ void function::add_to_namespace( not_implemented_function()); } } - + // The PyObject_GetAttrString() call above left an active error PyErr_Clear(); if (PyObject_SetAttr(ns, name.ptr(), attribute.ptr()) < 0) throw_error_already_set(); } +void function::add_to_namespace( + object const& name_space, char const* name_, object const& attribute, char const* doc) +{ + add_to_namespace(name_space, name_, attribute); + if (doc != 0) + { + object attr_copy(attribute); + attr_copy.attr("__doc__") = doc; + } +} + namespace { struct bind_return @@ -245,6 +258,24 @@ extern "C" handle_exception(bind_return(result, static_cast(func), args, kw)); return result; } + + static PyObject* function_get_doc(PyObject* op, void*) + { + function* f = downcast(op); + return incref(f->doc().ptr()); + } + + static int function_set_doc(PyObject* op, PyObject* doc) + { + function* f = downcast(op); + f->doc(doc ? object(python::detail::borrowed_reference(doc)) : object()); + return 0; + } + + static PyGetSetDef function_getsetlist[] = { + {"__doc__", function_get_doc, (setter)function_set_doc}, + {NULL} /* Sentinel */ + }; } PyTypeObject function_type = { @@ -277,8 +308,8 @@ PyTypeObject function_type = { 0, /* tp_iter */ 0, /* tp_iternext */ 0, /* tp_methods */ - 0, // func_memberlist, /* tp_members */ - 0, //func_getsetlist, /* tp_getset */ + 0, // func_memberlist, /* tp_members */ + function_getsetlist, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ function_descr_get, /* tp_descr_get */ @@ -290,4 +321,31 @@ PyTypeObject function_type = { 0 /* tp_new */ }; +object function_object_impl(py_function const& f, unsigned min_args, unsigned max_args) +{ + return python::object( + python::detail::new_non_null_reference( + new function(f, min_args, max_args))); +} + +handle<> function_handle_impl(py_function const& f, unsigned min_args, unsigned max_args) +{ + return python::handle<>( + allow_null( + new function(f, min_args, max_args))); +} + +BOOST_PYTHON_DECL void add_to_namespace( + object const& name_space, char const* name, object const& attribute) +{ + function::add_to_namespace(name_space, name, attribute); +} + +BOOST_PYTHON_DECL void add_to_namespace( + object const& name_space, char const* name, object const& attribute, char const* doc) +{ + function::add_to_namespace(name_space, name, attribute, doc); +} + + }}} // namespace boost::python::objects diff --git a/src/object/iterator.cpp b/src/object/iterator.cpp index 8b6da346..384d6845 100644 --- a/src/object/iterator.cpp +++ b/src/object/iterator.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include #include namespace boost { namespace python { namespace objects { @@ -18,9 +18,9 @@ static PyObject* identity(PyObject* args_, PyObject*) return x; } -BOOST_PYTHON_DECL handle<> identity_function() +BOOST_PYTHON_DECL object const& identity_function() { - static handle<> result(new objects::function(py_function(&identity), 1)); + static object result(function_object(&identity, 1)); return result; } diff --git a/src/object/pickle_support.cpp b/src/object/pickle_support.cpp index 3b14c8ea..6f37517f 100644 --- a/src/object/pickle_support.cpp +++ b/src/object/pickle_support.cpp @@ -54,9 +54,9 @@ namespace { } // namespace -handle<> make_instance_reduce_function() +object const& make_instance_reduce_function() { - static handle<> result(make_function(&instance_reduce)); + static object result(&instance_reduce); return result; } diff --git a/test/list.cpp b/test/list.cpp index a5c9bc87..7b0d2645 100644 --- a/test/list.cpp +++ b/test/list.cpp @@ -111,7 +111,7 @@ void exercise(list x, object y, object print) print(x); print("reverse sorted:"); - x.sort(handle<>(make_function(notcmp))); + x.sort(¬cmp); print(x); list w;