Chris@16: // Copyright David Abrahams 2002. Chris@16: // Distributed under the Boost Software License, Version 1.0. (See Chris@16: // accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: #ifndef CLASS_DWA200216_HPP Chris@16: # define CLASS_DWA200216_HPP Chris@16: Chris@16: # include Chris@16: Chris@16: # include Chris@16: Chris@16: # include Chris@16: # include Chris@16: Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: Chris@16: # include Chris@16: Chris@16: # if BOOST_WORKAROUND(__MWERKS__, <= 0x3004) \ Chris@16: /* pro9 reintroduced the bug */ \ Chris@16: || (BOOST_WORKAROUND(__MWERKS__, > 0x3100) \ Chris@16: && BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3201))) \ Chris@16: || BOOST_WORKAROUND(__GNUC__, < 3) Chris@16: Chris@16: # define BOOST_PYTHON_NO_MEMBER_POINTER_ORDERING 1 Chris@16: Chris@16: # endif Chris@16: Chris@16: # ifdef BOOST_PYTHON_NO_MEMBER_POINTER_ORDERING Chris@16: # include Chris@16: # include Chris@16: # endif Chris@16: Chris@16: namespace boost { namespace python { Chris@16: Chris@16: template class def_visitor; Chris@16: Chris@16: enum no_init_t { no_init }; Chris@16: Chris@16: namespace detail Chris@16: { Chris@16: // This function object is used with mpl::for_each to write the id Chris@16: // of the type a pointer to which is passed as its 2nd compile-time Chris@16: // argument. into the iterator pointed to by its runtime argument Chris@16: struct write_type_id Chris@16: { Chris@16: write_type_id(type_info**p) : p(p) {} Chris@16: Chris@16: // Here's the runtime behavior Chris@16: template Chris@16: void operator()(T*) const Chris@16: { Chris@16: *(*p)++ = type_id(); Chris@16: } Chris@16: Chris@16: type_info** p; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct is_data_member_pointer Chris@16: : mpl::and_< Chris@16: is_member_pointer Chris@16: , mpl::not_ > Chris@16: > Chris@16: {}; Chris@16: Chris@16: # ifdef BOOST_PYTHON_NO_MEMBER_POINTER_ORDERING Chris@16: # define BOOST_PYTHON_DATA_MEMBER_HELPER(D) , detail::is_data_member_pointer() Chris@16: # define BOOST_PYTHON_YES_DATA_MEMBER , mpl::true_ Chris@16: # define BOOST_PYTHON_NO_DATA_MEMBER , mpl::false_ Chris@16: # elif defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) Chris@16: # define BOOST_PYTHON_DATA_MEMBER_HELPER(D) , 0 Chris@16: # define BOOST_PYTHON_YES_DATA_MEMBER , int Chris@16: # define BOOST_PYTHON_NO_DATA_MEMBER , ... Chris@16: # else Chris@16: # define BOOST_PYTHON_DATA_MEMBER_HELPER(D) Chris@16: # define BOOST_PYTHON_YES_DATA_MEMBER Chris@16: # define BOOST_PYTHON_NO_DATA_MEMBER Chris@16: # endif Chris@16: Chris@16: namespace error Chris@16: { Chris@16: // Chris@16: // A meta-assertion mechanism which prints nice error messages and Chris@16: // backtraces on lots of compilers. Usage: Chris@16: // Chris@16: // assertion::failed Chris@16: // Chris@16: // where C is an MPL metafunction class Chris@16: // Chris@16: Chris@16: template struct assertion_failed { }; Chris@16: template struct assertion_ok { typedef C failed; }; Chris@16: Chris@16: template Chris@16: struct assertion Chris@16: : mpl::if_, assertion_failed >::type Chris@16: {}; Chris@16: Chris@16: // Chris@16: // Checks for validity of arguments used to define virtual Chris@16: // functions with default implementations. Chris@16: // Chris@16: Chris@16: template Chris@16: void not_a_derived_class_member(Default) {} Chris@16: Chris@16: template Chris@16: struct virtual_function_default Chris@16: { Chris@16: template Chris@16: static void Chris@16: must_be_derived_class_member(Default const&) Chris@16: { Chris@16: // https://svn.boost.org/trac/boost/ticket/5803 Chris@16: //typedef typename assertion > >::failed test0; Chris@16: # if !BOOST_WORKAROUND(__MWERKS__, <= 0x2407) Chris@16: typedef typename assertion >::failed test1; Chris@16: # endif Chris@16: typedef typename assertion >::failed test2; Chris@16: not_a_derived_class_member(Fn()); Chris@16: } Chris@16: }; Chris@16: } Chris@16: } Chris@16: Chris@16: // This is the primary mechanism through which users will expose Chris@16: // C++ classes to Python. Chris@16: template < Chris@16: class W // class being wrapped Chris@16: , class X1 // = detail::not_specified Chris@16: , class X2 // = detail::not_specified Chris@16: , class X3 // = detail::not_specified Chris@16: > Chris@16: class class_ : public objects::class_base Chris@16: { Chris@16: public: // types Chris@16: typedef objects::class_base base; Chris@16: typedef class_ self; Chris@16: typedef typename objects::class_metadata metadata; Chris@16: typedef W wrapped_type; Chris@16: Chris@16: private: // types Chris@16: Chris@16: // A helper class which will contain an array of id objects to be Chris@16: // passed to the base class constructor Chris@16: struct id_vector Chris@16: { Chris@16: typedef typename metadata::bases bases; Chris@16: Chris@16: id_vector() Chris@16: { Chris@16: // Stick the derived class id into the first element of the array Chris@16: ids[0] = detail::unwrap_type_id((W*)0, (W*)0); Chris@16: Chris@16: // Write the rest of the elements into succeeding positions. Chris@16: type_info* p = ids + 1; Chris@16: mpl::for_each(detail::write_type_id(&p), (bases*)0, (add_pointer*)0); Chris@16: } Chris@16: Chris@16: BOOST_STATIC_CONSTANT( Chris@16: std::size_t, size = mpl::size::value + 1); Chris@16: type_info ids[size]; Chris@16: }; Chris@16: friend struct id_vector; Chris@16: Chris@16: public: // constructors Chris@16: Chris@16: // Construct with the class name, with or without docstring, and default __init__() function Chris@16: class_(char const* name, char const* doc = 0); Chris@16: Chris@16: // Construct with class name, no docstring, and an uncallable __init__ function Chris@16: class_(char const* name, no_init_t); Chris@16: Chris@16: // Construct with class name, docstring, and an uncallable __init__ function Chris@16: class_(char const* name, char const* doc, no_init_t); Chris@16: Chris@16: // Construct with class name and init<> function Chris@16: template Chris@16: inline class_(char const* name, init_base const& i) Chris@16: : base(name, id_vector::size, id_vector().ids) Chris@16: { Chris@16: this->initialize(i); Chris@16: } Chris@16: Chris@16: // Construct with class name, docstring and init<> function Chris@16: template Chris@16: inline class_(char const* name, char const* doc, init_base const& i) Chris@16: : base(name, id_vector::size, id_vector().ids, doc) Chris@16: { Chris@16: this->initialize(i); Chris@16: } Chris@16: Chris@16: public: // member functions Chris@16: Chris@16: // Generic visitation Chris@16: template Chris@16: self& def(def_visitor const& visitor) Chris@16: { Chris@16: visitor.visit(*this); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: // Wrap a member function or a non-member function which can take Chris@16: // a T, T cv&, or T cv* as its first parameter, a callable Chris@16: // python object, or a generic visitor. Chris@16: template Chris@16: self& def(char const* name, F f) Chris@16: { Chris@16: this->def_impl( Chris@16: detail::unwrap_wrapper((W*)0) Chris@16: , name, f, detail::def_helper(0), &f); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: self& def(char const* name, A1 a1, A2 const& a2) Chris@16: { Chris@16: this->def_maybe_overloads(name, a1, a2, &a2); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: self& def(char const* name, Fn fn, A1 const& a1, A2 const& a2) Chris@16: { Chris@16: // The arguments are definitely: Chris@16: // def(name, function, policy, doc_string) Chris@16: // def(name, function, doc_string, policy) Chris@16: Chris@16: this->def_impl( Chris@16: detail::unwrap_wrapper((W*)0) Chris@16: , name, fn Chris@16: , detail::def_helper(a1,a2) Chris@16: , &fn); Chris@16: Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: self& def(char const* name, Fn fn, A1 const& a1, A2 const& a2, A3 const& a3) Chris@16: { Chris@16: this->def_impl( Chris@16: detail::unwrap_wrapper((W*)0) Chris@16: , name, fn Chris@16: , detail::def_helper(a1,a2,a3) Chris@16: , &fn); Chris@16: Chris@16: return *this; Chris@16: } Chris@16: Chris@16: // Chris@16: // Data member access Chris@16: // Chris@16: template Chris@16: self& def_readonly(char const* name, D const& d, char const* doc=0) Chris@16: { Chris@16: return this->def_readonly_impl(name, d, doc BOOST_PYTHON_DATA_MEMBER_HELPER(D)); Chris@16: } Chris@16: Chris@16: template Chris@16: self& def_readwrite(char const* name, D const& d, char const* doc=0) Chris@16: { Chris@16: return this->def_readwrite_impl(name, d, doc BOOST_PYTHON_DATA_MEMBER_HELPER(D)); Chris@16: } Chris@16: Chris@16: template Chris@16: self& def_readonly(char const* name, D& d, char const* doc=0) Chris@16: { Chris@16: return this->def_readonly_impl(name, d, doc BOOST_PYTHON_DATA_MEMBER_HELPER(D)); Chris@16: } Chris@16: Chris@16: template Chris@16: self& def_readwrite(char const* name, D& d, char const* doc=0) Chris@16: { Chris@16: return this->def_readwrite_impl(name, d, doc BOOST_PYTHON_DATA_MEMBER_HELPER(D)); Chris@16: } Chris@16: Chris@16: // Property creation Chris@16: # if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) Chris@16: template Chris@16: self& add_property(char const* name, Get fget, char const* docstr = 0) Chris@16: { Chris@16: base::add_property(name, this->make_getter(fget), docstr); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: self& add_property(char const* name, Get fget, Set fset, char const* docstr = 0) Chris@16: { Chris@16: base::add_property( Chris@16: name, this->make_getter(fget), this->make_setter(fset), docstr); Chris@16: return *this; Chris@16: } Chris@16: # else Chris@16: private: Chris@16: template Chris@16: self& add_property_impl(char const* name, Get fget, char const* docstr, int) Chris@16: { Chris@16: base::add_property(name, this->make_getter(fget), docstr); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: self& add_property_impl(char const* name, Get fget, Set fset, ...) Chris@16: { Chris@16: base::add_property( Chris@16: name, this->make_getter(fget), this->make_setter(fset), 0); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: public: Chris@16: template Chris@16: self& add_property(char const* name, Get fget) Chris@16: { Chris@16: base::add_property(name, this->make_getter(fget), 0); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: self& add_property(char const* name, Get fget, DocStrOrSet docstr_or_set) Chris@16: { Chris@16: this->add_property_impl(name, this->make_getter(fget), docstr_or_set, 0); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: self& Chris@16: add_property(char const* name, Get fget, Set fset, char const* docstr) Chris@16: { Chris@16: base::add_property( Chris@16: name, this->make_getter(fget), this->make_setter(fset), docstr); Chris@16: return *this; Chris@16: } Chris@16: # endif Chris@16: Chris@16: template Chris@16: self& add_static_property(char const* name, Get fget) Chris@16: { Chris@16: base::add_static_property(name, object(fget)); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: self& add_static_property(char const* name, Get fget, Set fset) Chris@16: { Chris@16: base::add_static_property(name, object(fget), object(fset)); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: self& setattr(char const* name, U const& x) Chris@16: { Chris@16: this->base::setattr(name, object(x)); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: // Pickle support Chris@16: template Chris@16: self& def_pickle(PickleSuiteType const& x) Chris@16: { Chris@16: error_messages::must_be_derived_from_pickle_suite(x); Chris@16: detail::pickle_suite_finalize::register_( Chris@16: *this, Chris@16: &PickleSuiteType::getinitargs, Chris@16: &PickleSuiteType::getstate, Chris@16: &PickleSuiteType::setstate, Chris@16: PickleSuiteType::getstate_manages_dict()); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: self& enable_pickling() Chris@16: { Chris@16: this->base::enable_pickling_(false); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: self& staticmethod(char const* name) Chris@16: { Chris@16: this->make_method_static(name); Chris@16: return *this; Chris@16: } Chris@16: private: // helper functions Chris@16: Chris@16: // Builds a method for this class around the given [member] Chris@16: // function pointer or object, appropriately adjusting the type of Chris@16: // the first signature argument so that if f is a member of a Chris@16: // (possibly not wrapped) base class of T, an lvalue argument of Chris@16: // type T will be required. Chris@16: // Chris@16: // @group PropertyHelpers { Chris@16: template Chris@16: object make_getter(F f) Chris@16: { Chris@16: typedef typename api::is_object_operators::type is_obj_or_proxy; Chris@16: Chris@16: return this->make_fn_impl( Chris@16: detail::unwrap_wrapper((W*)0) Chris@16: , f, is_obj_or_proxy(), (char*)0, detail::is_data_member_pointer() Chris@16: ); Chris@16: } Chris@16: Chris@16: template Chris@16: object make_setter(F f) Chris@16: { Chris@16: typedef typename api::is_object_operators::type is_obj_or_proxy; Chris@16: Chris@16: return this->make_fn_impl( Chris@16: detail::unwrap_wrapper((W*)0) Chris@16: , f, is_obj_or_proxy(), (int*)0, detail::is_data_member_pointer() Chris@16: ); Chris@16: } Chris@16: Chris@16: template Chris@16: object make_fn_impl(T*, F const& f, mpl::false_, void*, mpl::false_) Chris@16: { Chris@16: return python::make_function(f, default_call_policies(), detail::get_signature(f, (T*)0)); Chris@16: } Chris@16: Chris@16: template Chris@16: object make_fn_impl(T*, D B::*pm_, mpl::false_, char*, mpl::true_) Chris@16: { Chris@16: D T::*pm = pm_; Chris@16: return python::make_getter(pm); Chris@16: } Chris@16: Chris@16: template Chris@16: object make_fn_impl(T*, D B::*pm_, mpl::false_, int*, mpl::true_) Chris@16: { Chris@16: D T::*pm = pm_; Chris@16: return python::make_setter(pm); Chris@16: } Chris@16: Chris@16: template Chris@16: object make_fn_impl(T*, F const& x, mpl::true_, void*, mpl::false_) Chris@16: { Chris@16: return x; Chris@16: } Chris@16: // } Chris@16: Chris@16: template Chris@16: self& def_readonly_impl( Chris@16: char const* name, D B::*pm_, char const* doc BOOST_PYTHON_YES_DATA_MEMBER) Chris@16: { Chris@16: return this->add_property(name, pm_, doc); Chris@16: } Chris@16: Chris@16: template Chris@16: self& def_readwrite_impl( Chris@16: char const* name, D B::*pm_, char const* doc BOOST_PYTHON_YES_DATA_MEMBER) Chris@16: { Chris@16: return this->add_property(name, pm_, pm_, doc); Chris@16: } Chris@16: Chris@16: template Chris@16: self& def_readonly_impl( Chris@16: char const* name, D& d, char const* BOOST_PYTHON_NO_DATA_MEMBER) Chris@16: { Chris@16: return this->add_static_property(name, python::make_getter(d)); Chris@16: } Chris@16: Chris@16: template Chris@16: self& def_readwrite_impl( Chris@16: char const* name, D& d, char const* BOOST_PYTHON_NO_DATA_MEMBER) Chris@16: { Chris@16: return this->add_static_property(name, python::make_getter(d), python::make_setter(d)); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void initialize(DefVisitor const& i) Chris@16: { Chris@16: metadata::register_(); // set up runtime metadata/conversions Chris@16: Chris@16: typedef typename metadata::holder holder; Chris@16: this->set_instance_size( objects::additional_instance_size::value ); Chris@16: Chris@16: this->def(i); Chris@16: } Chris@16: Chris@16: inline void initialize(no_init_t) Chris@16: { Chris@16: metadata::register_(); // set up runtime metadata/conversions Chris@16: this->def_no_init(); Chris@16: } Chris@16: Chris@16: // Chris@16: // These two overloads discriminate between def() as applied to a Chris@16: // generic visitor and everything else. Chris@16: // Chris@16: // @group def_impl { Chris@16: template Chris@16: inline void def_impl( Chris@16: T* Chris@16: , char const* name Chris@16: , LeafVisitor Chris@16: , Helper const& helper Chris@16: , def_visitor const* v Chris@16: ) Chris@16: { Chris@16: v->visit(*this, name, helper); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void def_impl( Chris@16: T* Chris@16: , char const* name Chris@16: , Fn fn Chris@16: , Helper const& helper Chris@16: , ... Chris@16: ) Chris@16: { Chris@16: objects::add_to_namespace( Chris@16: *this Chris@16: , name Chris@16: , make_function( Chris@16: fn Chris@16: , helper.policies() Chris@16: , helper.keywords() Chris@16: , detail::get_signature(fn, (T*)0) Chris@16: ) Chris@16: , helper.doc() Chris@16: ); Chris@16: Chris@16: this->def_default(name, fn, helper, mpl::bool_()); Chris@16: } Chris@16: // } Chris@16: Chris@16: // Chris@16: // These two overloads handle the definition of default Chris@16: // implementation overloads for virtual functions. The second one Chris@16: // handles the case where no default implementation was specified. Chris@16: // Chris@16: // @group def_default { Chris@16: template Chris@16: inline void def_default( Chris@16: char const* name Chris@16: , Fn Chris@16: , Helper const& helper Chris@16: , mpl::bool_) Chris@16: { Chris@16: detail::error::virtual_function_default::must_be_derived_class_member( Chris@16: helper.default_implementation()); Chris@16: Chris@16: objects::add_to_namespace( Chris@16: *this, name, Chris@16: make_function( Chris@16: helper.default_implementation(), helper.policies(), helper.keywords()) Chris@16: ); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void def_default(char const*, Fn, Helper const&, mpl::bool_) Chris@16: { } Chris@16: // } Chris@16: Chris@16: // Chris@16: // These two overloads discriminate between def() as applied to Chris@16: // regular functions and def() as applied to the result of Chris@16: // BOOST_PYTHON_FUNCTION_OVERLOADS(). The final argument is used to Chris@16: // discriminate. Chris@16: // Chris@16: // @group def_maybe_overloads { Chris@16: template Chris@16: void def_maybe_overloads( Chris@16: char const* name Chris@16: , SigT sig Chris@16: , OverloadsT const& overloads Chris@16: , detail::overloads_base const*) Chris@16: Chris@16: { Chris@16: // convert sig to a type_list (see detail::get_signature in signature.hpp) Chris@16: // before calling detail::define_with_defaults. Chris@16: detail::define_with_defaults( Chris@16: name, overloads, *this, detail::get_signature(sig)); Chris@16: } Chris@16: Chris@16: template Chris@16: void def_maybe_overloads( Chris@16: char const* name Chris@16: , Fn fn Chris@16: , A1 const& a1 Chris@16: , ...) Chris@16: { Chris@16: this->def_impl( Chris@16: detail::unwrap_wrapper((W*)0) Chris@16: , name Chris@16: , fn Chris@16: , detail::def_helper(a1) Chris@16: , &fn Chris@16: ); Chris@16: Chris@16: } Chris@16: // } Chris@16: }; Chris@16: Chris@16: Chris@16: // Chris@16: // implementations Chris@16: // Chris@16: Chris@16: template Chris@16: inline class_::class_(char const* name, char const* doc) Chris@16: : base(name, id_vector::size, id_vector().ids, doc) Chris@16: { Chris@16: this->initialize(init<>()); Chris@16: // select_holder::assert_default_constructible(); Chris@16: } Chris@16: Chris@16: template Chris@16: inline class_::class_(char const* name, no_init_t) Chris@16: : base(name, id_vector::size, id_vector().ids) Chris@16: { Chris@16: this->initialize(no_init); Chris@16: } Chris@16: Chris@16: template Chris@16: inline class_::class_(char const* name, char const* doc, no_init_t) Chris@16: : base(name, id_vector::size, id_vector().ids, doc) Chris@16: { Chris@16: this->initialize(no_init); Chris@16: } Chris@16: Chris@16: }} // namespace boost::python Chris@16: Chris@16: # undef BOOST_PYTHON_DATA_MEMBER_HELPER Chris@16: # undef BOOST_PYTHON_YES_DATA_MEMBER Chris@16: # undef BOOST_PYTHON_NO_DATA_MEMBER Chris@16: # undef BOOST_PYTHON_NO_MEMBER_POINTER_ORDERING Chris@16: Chris@16: #endif // CLASS_DWA200216_HPP