diff --git a/include/boost/python/class.hpp b/include/boost/python/class.hpp new file mode 100644 index 00000000..8e921780 --- /dev/null +++ b/include/boost/python/class.hpp @@ -0,0 +1,288 @@ +// 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 CLASS_DWA200216_HPP +# define CLASS_DWA200216_HPP + +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +namespace boost { namespace python { + +namespace detail +{ + struct write_type_id; + + template + struct select_held_type; + + template + struct has_noncopyable; + + // Register a to_python converter for a class T, depending on the + // type of the first (tag) argument. The 2nd argument is a pointer + // to the type of holder that must be created. The 3rd argument is a + // reference to the Python type object to be created. + template + static inline void register_copy_constructor(mpl::bool_t const&, Holder*, ref const& obj, T* = 0) + { + objects::class_wrapper x(obj); + } + + // Tag dispatched to have no effect. + template + static inline void register_copy_constructor(mpl::bool_t const&, Holder*, ref const&, T* = 0) + { + } +} + +// +// class_ +// +// This is the primary mechanism through which users will expose +// C++ classes to Python. The three template arguments are: +// +template < + class T // class being wrapped + , class X1 // = detail::not_specified + , class X2 // = detail::not_specified + , class X3 // = detail::not_specified + > +class class_ : public objects::class_base +{ + typedef class_ self; + BOOST_STATIC_CONSTANT(bool, is_copyable = (!detail::has_noncopyable::value)); + + typedef typename detail::select_held_type< + X1, typename detail::select_held_type< + X2, typename detail::select_held_type< + X3 + >::type>::type>::type held_type; + + public: + // Automatically derive the class name - only works on some + // compilers because type_info::name is sometimes mangled (gcc) + class_(); + + // Construct with the class name. [ Would have used a default + // argument but gcc-2.95.2 choked on typeid(T).name() as a default + // parameter value] + class_(char const* name); + + + // Wrap a member function or a non-member function which can take + // a T, T cv&, or T cv* as its first parameter, or a callable + // python object. + template + self& def(char const* name, F f) + { + // Use function::add_to_namespace to achieve overloading if + // appropriate. + objects::function::add_to_namespace( + this->object(), name, + ref(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) + ))); + return *this; + } + + template + self& def(char const* name, Fn fn, CallPolicy policy) + { + 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; + } + + // Define the constructor with the given Args, which should be an + // MPL sequence of types. + template + self& def_init(Args const&) + { + def("__init__", + 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( + policy + // Using runtime type selection works around a CWPro7 bug. + , objects::select_holder((held_type*)0).get() + ) + ); + return *this; + } + + // Define the default constructor. + self& def_init() + { + this->def_init(mpl::type_list<>::type()); + return *this; + } + + // + // Data member access + // + template + self& def_readonly(char const* name, D T::*pm) + { + ref fget(make_getter(pm)); + this->add_property(name, fget); + return *this; + } + + template + self& def_readwrite(char const* name, D T::*pm) + { + ref fget(make_getter(pm)); + ref fset(make_setter(pm)); + this->add_property(name, fget, fset); + return *this; + } + + // return the underlying object +// ref object() const; + + private: // types + typedef objects::class_id class_id; + + typedef typename detail::select_bases::type + >::type + >::type bases; + + // A helper class which will contain an array of id objects to be + // passed to the base class constructor + struct id_vector + { + typedef objects::class_id class_id; + id_vector() + { + // Stick the derived class id into the first element of the array + ids[0] = converter::undecorated_type_id(); + + // Write the rest of the elements into succeeding positions. + class_id* p = ids + 1; + mpl::for_each::execute(&p); + } + + BOOST_STATIC_CONSTANT( + std::size_t, size = mpl::size::value + 1); + class_id ids[size]; + }; + friend struct id_vector; +}; + + +// +// implementations +// +template +inline class_::class_() + : class_base(typeid(T).name(), id_vector::size, id_vector().ids) +{ + // register converters + objects::register_class_from_python(); + + detail::register_copy_constructor( + mpl::bool_t() + , objects::select_holder((held_type*)0).get() + , this->object()); +} + +template +inline class_::class_(char const* name) + : class_base(name, id_vector::size, id_vector().ids) +{ + // register converters + objects::register_class_from_python(); + + detail::register_copy_constructor( + mpl::bool_t() + , objects::select_holder((held_type*)0).get() + , this->object()); +} + +namespace detail +{ + // This is an mpl BinaryMetaFunction object with a runtime behavior, + // which is to write the id of the type which is passed as its 2nd + // compile-time argument into the iterator pointed to by its runtime + // argument + struct write_type_id + { + // The first argument is Ignored because mpl::for_each is still + // currently an accumulate (reduce) implementation. + template struct apply + { + // also an artifact of accumulate-based for_each + typedef void type; + + // Here's the runtime behavior + static void execute(converter::undecorated_type_id_t** p) + { + *(*p)++ = converter::undecorated_type_id(); + } + }; + }; + + + template + struct has_noncopyable + : type_traits::ice_or< + is_same::value + , is_same::value + , is_same::value> + {}; + + + template + struct select_held_type + : mpl::select_type< + type_traits::ice_or< + specifies_bases::value + , is_same::value + >::value + , Prev + , T + > + { + }; +} + +}} // namespace boost::python + +#endif // CLASS_DWA200216_HPP